乐趣区

当面试官问你你有没有打造过属于自己的UI组件库

开篇

西风吹老洞庭波,一夜湘君白发多。
醉后不知天在水,满船清梦压星河。

前言

身为程序员, 还没有自己的包, 总感觉缺点什么, 女朋友和包至少占一样吧. 正如上战场没有扛枪的士兵, 吃饭少了筷子一样, 令人心情不愉悦. 同时经常会有面试官会问一个犀利的问题, 你有自己开源项目么? 你写过公司自己的 UI 组件么? 如同雷劈, 总觉得比别人矮一截, 那么今天就以 hekr-ui 为例, 介绍一下如何打造自己的 UI 库吧

  • 文档地址
  • 项目源码

选型

我们的目标是构建一个以 Vue 为基础基于 element-ui 的 UI 框架

  • 文档选用 Vuepress 构建, 简单便捷
  • 打包选择 gitlab CI , 本文以 travis 为例
  • 初始化采用 vue-cli 3.0pugsass等相关依赖和插件(自行探索)

目的

  1. 快速构建属于❤️自己 npm
  2. 熟悉打包???? 命令及其语法
  3. 熟练掌握自动化???? 构建
  4. 为社区贡献自己一份脚印????

初步构思

启动一个项目

1. 初始化一个项目

这里推荐使用Vue CLI 来进行快速构建

vue create hekr-ui

我们选择默认配置就可以了

2. 关联代码到你的库

git可以很好对代码版本进行管理

  • 当你初始化库时
echo "# hekr-ui" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/xkloveme/hekr-ui.git
git push -u origin master
  • 关联本地库时
git remote add origin https://github.com/xkloveme/hekr-ui.git
git push -u origin master

当然我们选择第二种. 记得把 node_modules 忽略

配置你的项目

1. 添加相关依赖

本文以 yarn 为主, 当然 npm 也是????OK 的

我们以 vuepress 为主编写文档, 当然这是非必须的, 如果您只想发一个包, 可以省略此步, 必要的 demo 和测试会有极大的方便

# 将 VuePress 作为一个本地依赖安装
yarn add -D vuepress # 或者:npm install -D vuepress

# 新建一个 docs 文件夹
mkdir docs

# 新建一个 markdown 文件
echo '# Hello VuePress!' > docs/README.md

# 开始写作
npx vuepress dev docs

接着,在 package.json 里加一些脚本:

{
  "scripts": {
    "docs:dev": "vuepress dev docs",
    "docs:build": "vuepress build docs"
  }
}

然后就可以开始写作了:

yarn docs:dev # 或者:npm run docs:dev

要生成静态的 HTML 文件,运行:

yarn docs:build # 或者:npm run docs:build

添加其他依赖, 常用语法

// 安装指定包
yarn add *** 
// 安装所有包, 注意和 npm 的区别
yarn

注意⚠️这两者的区别 dependenciesdevDependencies

  1. --save 将依赖的名称、版本要求添加到 dependencies
  2. --save-dev 将依赖的名称、版本要求添加到 devDependencies

2. 一些约定俗成的目录结构

  • 在使用 vuepress 开发时, 约定了一些目录结构
.
├── docs
│   ├── .vuepress (可选的)
│   │   ├── components (可选的)
│   │   ├── theme (可选的)
│   │   │   └── Layout.vue
│   │   ├── public (可选的)
│   │   ├── styles (可选的)
│   │   │   ├── index.styl
│   │   │   └── palette.styl
│   │   ├── templates (可选的, 谨慎配置)
│   │   │   ├── dev.html
│   │   │   └── ssr.html
│   │   ├── config.js (可选的)
│   │   └── enhanceApp.js (可选的)
│   │ 
│   ├── README.md
│   ├── guide
│   │   └── README.md
│   └── config.md
│ 
└── package.json
  • 在本项目中目录结构为

template
├─ docs
│    └─ .vuepress            # 配置、演示组件、静态资源
│    │    ├─ compnents        # 演示组件
│    │    |    └─ demo          # demo 组件
│    │    ├─ public           # 静态资源
│    │    |    └─ images        # 图片文件
│    │    |    └─ scss          # 样式文件
│    │    ├─ config.js        # 配置文件
│    │    └─ enhanceApp       # 引入文件
|    ├─ compnent             # 组件 md 文件
|    └─ README              # 首页 md
├─ packages
│    ├─ index.js             # 组件 index.js
│    └─ hk-countup           # countup 组件
├─ public
└─ package.json

3. 修改你的 package.json 文件

这个文件是项目的灵魂????, 是最重要的文件之一. 具体字段参考 packagejson

  • 修改主入口main

main字段指定了加载的入口文件,require('moduleName')就会加载这个文件。这个字段的默认值是模块根目录下面的index.js

"main": "dist/hekr-ui.umd.min.js"

你可以通过下面的命令将一个单独的入口构建为一个库

vue-cli-service build --target lib --name myLib [entry]

运行结果为:

  File                     Size                     Gzipped

  dist/hk-ui.umd.min.js    13.64 KiB                5.31 KiB
  dist/hk-ui.umd.js        43.87 KiB                11.37 KiB
  dist/hk-ui.common.js     43.49 KiB                11.25 KiB
  dist/hk-ui.css           0.54 KiB                 0.29 KiB
  • 添加 lib 命令
    "lib": "vue-cli-service build --target lib --name hk-ui --dest dist ./src/packages/index.js"

这个入口可以是一个 .js 或一个 .vue 文件。如果没有指定入口,则会使用 src/App.vue

构建一个库会输出:

  • dist/myLib.common.js:一个给打包器用的 CommonJS 包 (不幸的是,webpack 目前还并没有支持 ES modules 输出格式的包)
  • dist/myLib.umd.js:一个直接给浏览器或 AMD loader 使用的 UMD 包
  • dist/myLib.umd.min.js:压缩后的 UMD 构建版本
  • dist/myLib.css:提取出来的 CSS 文件 (可以通过在 vue.config.js 中设置 css: {extract: false} 强制内联)

4. 文档配置

项目启动之后需要我们配置我们的vuepress

/*
 * @describe: 配置文件 config.js
 * @Author: superDragon
 * @Date: 2019-10-09 23:25:49
 * @LastEditors: superDragon
 * @LastEditTime: 2019-10-10 18:49:25
 */
let component = [
  'hk-button',
  'hk-card'
]
module.exports = {
  base: '/hekr-ui/',
  title: 'hekr-ui',
  description: 'hekr-ui',
  themeConfig: {
    nav: [{ text: '首页', link: '/'},
      {
        text: '组件',
        link: '/component/hk-button'
      }
    ],
    sidebar: {'/component/': component},
    lastUpdated: '最后更新',
    repo: '',
    repoLabel: 'GitLab'
  },
  plugins: [],
  serviceWorker: true
}

当我们能够成功运行下面时

    "docs:dev": "vuepress dev docs",
    "docs:build": "vuepress build docs",
  • 本地运行
yarn docs:dev # 或者:npm run docs:dev
  • 打包
yarn docs:build # 或者:npm run docs:build

5. 持续集成

GitHub PagesTravis CI 为例

  • 打包后放置在项目的 docs 目录中的 dist 中, 注意⚠️区分;
  • 使用的是默认的构建输出位置;
  • VuePress 以本地依赖的形式被安装到你的项目中,并且配置了如下的 npm scripts:
{
  "scripts": {"docs:build": "vuepress build docs"}
}
  1. docs/.vuepress/config.js 中设置正确的 base这里我们设置/hekr-ui/ ????。

    如果你打算发布到 https://<USERNAME>.github.io/,则可以省略这一步,因为 base 默认即是 "/"

    如果你打算发布到 https://<USERNAME>.github.io/<REPO>/(也就是说你的仓库在 https://github.com/<USERNAME>/<REPO>),则将 base 设置为 "/<REPO>/"

  2. 在你的项目中,创建一个如下的 .travis.yml 文件????:
language: node_js
node_js:
  - '8'

install:
  - npm install

script:
  - npm run build

after_success:
  - cd ./docs/.vuepress/dist
  - git init
  - git config --global user.name "${U_NAME}"
  - git config --global user.email "${U_EMAIL}"
  - git add .
  - git commit -m "????‍Automatically update from travis-ci ????‍"
  - git push --quiet --force  "https://${GH_TOKEN}@${GH_REF}" master:${P_BRANCH}

branches:
  only:
    - master

notifications:
  email:
    - xkloveme@163.com
  on_failure: always

# Note: you should set Environment Variables here or 'Settings' on travis-ci.org
env:
  global:
    # 我将其添加到了 travis-ci 的环境变量中
    - U_NAME: xkloveme
    - U_EMAIL: xkloveme@qq.com
    - P_BRANCH: gh-pages
    - GH_REF: github.com/xkloveme/vue-v-xxx.git
  1. 注册 githubtravis 和配置 travis 相关, 启用构建, 自行 Google 传送门
  2. 更多配置参考 vuepress 部署

实践

完善组件并打包

以编写 hk-button 组件为例, 并导出

  1. 添加组件及导出
<template lang="pug">
el-tooltip(effect="dark" v-if="tips" :content="tips" placement="top-start")
  el-button.hk-button(:size="size" :type="type" v-bind="$attrs" @click="handleClick")
    slot
el-button.hk-button(:size="size" v-else :type="type" v-bind="$attrs" @click="handleClick")
  slot
</template>

<script>
import {Debounce} from './../util/debounce'
export default {
  name: 'hk-button',
  props: {
    type: {
      type: String,
      default: 'primary'
    },
    size: {
      type: String,
      default: 'medium'
    },
    tips: {
      type: String,
      default: null
    }
  },
  methods: {handleClick: Debounce(function (e) {this.$emit('click', e)
    }, 200)
  }
}
</script>

<style lang="scss">
.hk-button {
  i + span {padding-left: 10px;}
}
</style>
  1. 导出组件
import HkButton from './hk-button'

export default HkButton
  1. 导出为install
/*
 * @describe: 主入口, 导出 install
 * @Author: superDragon
 * @Date: 2019-10-09 23:21:11
 * @LastEditors: superDragon
 * @LastEditTime: 2019-10-10 19:09:57
 */
import HkButton from './hk-button'
import HKcard from './hk-card'

const install = Vue => {Vue.component(HkButton.name, HkButton)
  Vue.component(HKcard.name, HKcard)
}

if (typeof window !== 'undefined' && window.Vue) {install(window.Vue)
}

export {
  HkButton,
  HKcard
}

export default {install}

上传自己的npm

注册®️并切换到官方 npm

注册登陆npm

npm adduser        // 回车后, 弹出 Username:  
Username:          // 输入你在官网注册时的用户名, 回车
Password:          // 输入官网注册的密码, 密码看不见, 请确保你输的密码正确, 回车
Email:(this is Public)    // 输入官网注册时绑定的邮箱, 回车

上传

npm publish        // 此处上传命令, 回车

这样一个 hekr-ui 就发布完成了

撤销

24 小时内撤销也是很简单的.

npm unpublish --force 

大功告成

Let’s enjoy the taste of life, if we feel, the more we will live longer.

觉得不错的话给个star

  • 本文演示库地址 hekr-ui
  • 文档地址
  • 项目源码
退出移动版