0.1.4 • Published 11 months ago

vue-comp-business v0.1.4

Weekly downloads
-
License
MIT
Repository
-
Last release
11 months ago

使用vue-cli开发业务组件库

一、前言

​ 随着业务的持续完善,前端项目的体积也在不断变大。如何有效的对代码进行管理、公共组件和业务组件的复用是需要考虑的问题。为了去较好的解决这个问题,看了很多的方案,各有各的优点,各有各的适用场景。

​ 突然想到,既然是组件库,为何不去看那些优秀的组件库源码呢?于是,花了些时间,把Element UI的源码仔细的看了下,获益匪浅,这里也推荐大家先去学习学习。最后,以它的结构为主,做了一定调整,完成了本示例项目。

二、效果演示

1、项目使用
/** 全量引入 **/
import vueCompBusiness from 'vue-comp-business';
import 'vue-comp-business/lib/css/index.css';
Vue.use(vueCompBusiness);

/** 按需引入 **/
// 1、安装babel
npm install babel-plugin-component -D
// 2、main.js
import { CbButton } from 'vue-comp-business';
Vue.use(CbButton);

// 3、babel.config.js
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  // vue-comp-business组件按需加载
  plugins: [
    [
      'import',
      {
        libraryName: 'vue-comp-business',
        // 定义寻找组件css文件路径逻辑,不调整的话,会找cb-button.css文件
        customStyleName: (name) => {
          console.log('customStyleName', name)
          return `vue-comp-business/lib/css/${name.slice(3)}.css`
        },
        
        // 定义寻找组件路径逻辑,不调整的话,会找cb-button.js文件
        customName: (name) => {
          console.log('customName', name)
          return `vue-comp-business/lib/${name.slice(3)}`
        }
      }
    ]
  ]
}
2、效果截图

img

img

img

三、实现步骤

​ 涉及到的知识点有:Vue Cli、Vue、Vuepress、scss、bem,不熟悉的可以先去官网熟悉熟悉。

1、代码结构
vue-comp-business
├─ build	--------------------------------------------------------- 打包配置文件夹
│  ├─ config.dev.js	-------------------------------------------- 测试环境打包配置文件
│  └─ config.prod.js	---------------------------------------- 测试环境打包配置文件

├─ deploy	------------------------------------------------------ 文档打包配置文件夹
│  └─ docs.sh	---------------------------------------------------- 文档打包配置文件
│
├─ docs	---------------------------------------------------------- Vuepress相关文件夹
│  ├─ .vuepress	------------------------------------------------------- Vuepress默认
│  │  ├─ components	------------------------------------------ Vuepress拓展组件文件夹
│  │  │  ├─ press-row.vue	------------------------------------------------- 行组件
│  │  │  └─ source-block.vue	---------------------------------------- 代码查看组件
│  │  ├─ config.js	------------------------------------------ Vuepress菜单导航等配置
│  │  ├─ enhanceApp.js	--------------------------------------- 异步导入第三方组件实现
│  │  └─ public	--------------------------------------------- Vuepress 公共资源文件夹
│  │     └─ element.png	------------------------------------------------------ logo
│  ├─ guide	---------------------------------------------------------- 导航资源文件夹
│  │  ├─ CbButton.md	----------------------------------------------- 自定义按钮md
│  │  ├─ CbPanel.md	--------------------------------------------------- 自定义面板md
│  │  └─ README.md	-------------------------------------------------- guide 主页md
│  └─ README.md	---------------------------------------------------- Vuepress主页md
│
├─ examples	------------------------------------------------------ 开发环境示例文件夹
│  ├─ App.vue	------------------------------------------------------- 开发环境主页
│  └─ main.js	------------------------------------------------------- 开发环境入口
│
├─ lib	---------------------------------------- 打包后资源存放文件夹(普通模式\UMD模式)
│  ├─ button.js
│  ├─ css
│  │  ├─ button.css
│  │  ├─ index.css
│  │  └─ panel.css
│  ├─ index.js
│  └─ panel.js
│
├─ packages	--------------------------------------------------- 业务组件库统一文件夹
│  ├─ components	------------------------------------------------ 业务组件文件夹
│  │  ├─ button	---------------------------------------------------- 按钮组件文件夹
│  │  │  ├─ index.js	------------------------------------------------- 组件入口
│  │  │  └─ src
│  │  │     └─ button.vue	----------------------------------------- 按钮组件实现
│  │  └─ panel
│  │     ├─ index.js
│  │     └─ src
│  │        └─ panel.vue
│  │  ├─ index.js	------------------------------------------------- 全部组件入口
│  └─ css	---------------------------------------------------- 组件css统一文件夹
│     ├─ common	-------------------------------------------------------- 变量scss
│     │  └─ var.scss	----------------------------------------- 测试环境打包配置
│     ├─ fonts	------------------------------------------------------------ 字体
│     │  ├─ element-icons.ttf
│     │  └─ element-icons.woff
│     ├─ mixins	-------------------------------------------------------- scss混入
│     │  ├─ config.scss	--------------------------------------------- bem前缀配置
│     │  ├─ function.scss	---------------------------------------- 工具方法scss
│     │  ├─ mixins.scss	-------------------------------------------- 工具混入scss
│     │  └─ utils.scss	---------------------------------------- 常用样式混入scss
│     ├─ index.scss	--------------------------------------------- 全部组件样式入口
│     ├─ button.scss	----------------------------------------------- 按钮样式
│     └─ panel.scss	--------------------------------------------------- 面板样式
│
├─ public	------------------------------------------------------ 静态资源文件夹
│  ├─ favicon.ico
│  └─ index.html	-------------------------------------------------- html模板
│
├─ vue.config.js	--------------------------------------------------- 打包配置
├─ jsconfig.json	-------------------------------------------- 文件路径识别配置
├─ components.json	------------------------------------------------ 组件路径配置
├─ .gitignore
├─ .npmignore
├─ babel.config.js	-------------------------------------------------- babel配置
├─ package-lock.json
├─ package.json
├─ README.md
2、package.json

​ 这里使用的脚手架版本是4.5,使用5版本的脚手架时,要么sass有问题,有么vuepress文档运行时出错,直接放弃了,哈哈...

{
  "name": "vue-comp-business",
  "version": "0.1.0",
  "private": true,
  "/**main**/": "注释:指定包的入口,npm下载后看到的入口",
  "main": "./lib/index.js",
  "style": "./lib/theme/index.css",
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "build:umd": "vue-cli-service build --target lib --dest lib --name vue-comp-business packages/components/index.js",
    "docs:dev": "vuepress dev docs",
    "docs:build": "vuepress build docs",
    "docs:deploy": "bash ./deploy/docs.sh"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "vue": "^2.6.11"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vuepress/plugin-back-to-top": "^1.9.7",
    "node-sass": "^4.14.1",
    "sass": "^1.49.0",
    "sass-loader": "^7.3.1",
    "vue-template-compiler": "^2.6.11",
    "vuepress": "^1.9.7"
  },
  "author": "admin",
  "license": "MIT"
}
3、打包配置
  • dev打包配置
const path = require('path');

module.exports = {
  configureWebpack: {
    entry: path.join(__dirname, '../examples/main.js')
  }
};
  • prod打包配置
// components.json
{
  "button": "./packages/components/button/index.js",
  "panel": "./packages/components/panel/index.js",
  "index": "./packages/components/index.js"
}
const path = require('path');
const components = require('../components.json');

const resolve = dir => path.join(__dirname, '../', dir);

// 获取每个组件的绝对路径
const getComponentEntries = () => {
  const entryKeys = Object.keys(components);

  entryKeys.forEach(key => {
    components[key] = resolve(components[key]);
  });

  return components;
};

// { button: '/Users/xxx/packages/button/index.js' }
const componentEntries = getComponentEntries();

module.exports = {
  outputDir: resolve('lib'),
  configureWebpack: {
    entry: componentEntries,
    output: {
      //  文件名称
      filename: '[name].js',
      //  构建依赖类型
      libraryTarget: 'umd',
      //  库中被导出的项
      libraryExport: 'default',
      //  引用时的依赖名
      library: 'vueTestComp'
    }
  },
  // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建
  productionSourceMap: false,
  css: {
    extract: {
      filename: 'css/[name].css' //在lib文件夹中建立 theme 文件夹中,生成对应的css文件。
    }
  },
  /**
   * 删除splitChunks,因为每个组件是独立打包,不需要抽离每个组件的公共js出来。
   * 删除copy,不要复制public文件夹内容到lib文件夹中。
   * 删除html,只打包组件,不生成html页面。
   * 删除preload以及prefetch,因为不生成html页面,所以这两个也没用。
   * 删除hmr,删除热更新。
   * 删除自动加上的入口App。
   */
  chainWebpack: config => {
    config.optimization.delete('splitChunks');
    config.plugins.delete('copy');
    config.plugins.delete('html');
    config.plugins.delete('preload');
    config.plugins.delete('prefetch');
    config.plugins.delete('hmr');
    config.entryPoints.delete('app');
  }
};
4、按钮组件的实现
<template>
    <button
        class="cb-button"
        :class="[
            type ? 'cb-button--' + type : ''
        ]"
     >
        <span><slot /></span>
    </button>
</template>

<script>
export default {
    name: 'CbButton',
    props: {
        type: {
            type: String,
            default: 'default'
        }
    }
}
</script>

<style lang="scss" src="../../../css/button.scss"></style>
// button.scss文件

@charset "UTF-8";
@import "common/var";
@import "mixins/mixins";

@include b(button) {
    display: inline-block;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    background: $--button-default-background-color;
    border: $--border-base;
    border-color: $--button-default-border-color;
    color: $--button-default-font-color;
    -webkit-appearance: none;
    text-align: center;
    box-sizing: border-box;
    outline: none;
    margin: 0;
    padding: $--button-small-padding-vertical;
    // 两个按钮间距10像素
    & + & {
        margin-left: 10px;
    }

    &:hover,
    &:focus {
      color: $--color-primary;
      border-color: $--color-primary-light-7;
      background-color: $--color-primary-light-9;
    }

    @include m(primary) {

        color: $--button-primary-font-color;
        background-color: $--button-primary-background-color;
        border-color: $--button-primary-border-color;
      
        &:hover,
        &:focus {
          background: mix($--color-white, $--button-primary-background-color, $--button-hover-tint-percent);
          border-color: mix($--color-white, $--button-primary-border-color, $--button-hover-tint-percent);
          color: $--button-primary-font-color;
        }
    }

    @include m(success) {
        color: $--button-success-font-color;
        background-color: $--button-success-background-color;
        border-color: $--button-success-border-color;
      
        &:hover,
        &:focus {
          background: mix($--color-white, $--button-success-background-color, $--button-hover-tint-percent);
          border-color: mix($--color-white, $--button-success-border-color, $--button-hover-tint-percent);
          color: $--button-primary-font-color;
        }
    }
}
// 按钮组件入口
import CommonButton from './src/button.vue'

CommonButton.install = (Vue) => {
    Vue.component(CommonButton.name, CommonButton)
}

export default CommonButton
5、全部组件导出
import CbButton from './button/index.js'
import CbPanel from './panel/index.js'

const components = [
    CbButton,
    CbPanel
]

// 全局引入: 引入的组件是个对象时,必须要有install函数
const install = (Vue) => {

    components.forEach(component => {
        Vue.component(component.name, component);
    });
}

/* istanbul ignore if */
if (typeof window !== 'undefined' && window.Vue) {
    install(window.Vue);
}

export default {
    install,
    CbButton,
    CbPanel
}
6、开发环境测试
  • App.vue
<template>
  <div id="app">
    <div class="mb10">
      <CbButton>按钮组件测试</CbButton>
      <CbButton type="primary">按钮组件测试</CbButton>
      <CbButton type="success">按钮组件测试</CbButton>
    </div>
    
    <CbPanel></CbPanel>
  </div>
</template>

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

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  margin-top: 60px;
}
.mb10 {
  margin-bottom: 10px;
}
</style>
  • main.js
import Vue from 'vue';
import App from './App.vue';
// 批量注册组件
import CbComponent from '../packages/components';
import '../packages/css/index.scss';
Vue.use(CbComponent);
console.log(CbComponent, Vue)

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount('#app');
7、文档编写
  • 菜单等配置

    module.exports = {
      title: 'vue-comp-bussiness',
      description: 'vue-comp-bussiness 组件库文档',
      markdown: {
        lineNumbers: true
      },
      base: '/vue-comp-bussiness/',
      locales: {
        '/': {
          lang: 'zh-CN',
          title: '个人业务组件库',
          description: '这是国际化相关配置'
        },
        '/en/': {
          lang: 'en-US',
          title: 'vue-comp-business',
          description: 'this is locales config'
        }
      },
      themeConfig: {
        locales: {
          '/': {
            selectText: '选择语言',
            label: '简体中文',
            nav: [
              {
                text: '指南',
                link: '/guide/'
              },
              {
                text: 'github',
                link: 'https://github.com'
              }
            ],
            sidebar: {
              '/guide/': [
                ['', '介绍'],
                {
                  title: '组件',
                  children: [
                    ['../guide/CbButton.md', 'CbButton'],
                    ['../guide/CbPanel.md', 'CbPanel']
                  ]
                }
              ]
            }
          }
          // '/en/': {
          //   selectText: 'Languages',
          //   label: 'English',
          //   nav: [
          //     {
          //       text: 'guide',
          //       link: '/en/guide/'
          //     },
          //     {
          //       text: 'github',
          //       link: 'https://github.com'
          //     }
          //   ],
          //   sidebar: {
          //     '/en/guide/': [
          //       ['', 'introduction'],
          //       {
          //         title: 'Components',
          //         children: [
          //           ['../guide/Button.md', 'Button'],
          //           ['../guide/Card.md', 'Card']
          //         ]
          //       }
          //     ]
          //   }
          // }
        }
      },
      plugins: ['@vuepress/back-to-top']
    };
  • 第三方组件导入

    // 引入打包后的样式和文件。
    import '../../lib/css/index.css';
    
    export default async ({ Vue, options, router, siteData, isServer }) => {
      if (!isServer) {
        // 直接导入 window is not defined  原因就是编译的时候需要 node.js 服务端渲染。所以要改成异步导入
        await import('../../lib').then(vueComp => {
          Vue.use(vueComp);
        });
      }
    };

四、npm推送

1、关键备注

package.json :配置信息。

  • private: 选项改为 false;当 private 为 true 时,是不允许发布到 npm 的。
  • name: 当前应用的名称或库名称。
  • version: 原则上每次发布版本,版本号都应该是递增的。
  • main:项目入口文件。例如:./lib/test-comp-base.umd.min.js
  • author: 作者名称。
  • license:使用哪种开源协议。

    .npmignore :过滤不需要上传的文件

2、推送
  1. 之前没有提交到npm的先做准备工作:https://segmentfault.com/a/1190000015939001

  2. cmd窗口添加全局用户信息配置:npm adduser

    -- 426错误:镜像地址切换一下,还不行,检查一下网络问题
    npm config set registry https://registry.npmjs.org/
  3. 在项目根路径运行,npm publish

0.1.4

11 months ago

0.1.3

11 months ago

0.1.2

11 months ago

0.1.1

11 months ago

0.1.0

11 months ago