In daily business development, most of us encapsulate our own components, either business components or UI components. Of course, there are many excellent open source UI component libraries, such as Ant Design, Element UI, Material UI, etc., which can basically meet our daily development needs. However, the same world is not the same designer, and UI designers of different companies have their own different design styles. Therefore, in view of this situation, it is necessary to encapsulate and implement a SET of UI component libraries in line with their own company’s design concept.

This article gives a brief description of how to build a UI component library and documentation from scratch. The content of this article involves the process, tools and configuration of component library construction, referring to Element UI and iView.

UI component library address: zyl- UI

Document address: zyl-docs

Project structures,

Vue-cli initialization project

vue create zyl-ui
Copy the code
? Please pick a preset:
  default (babel, eslint)
> Manually select features
Copy the code

Select the features you want to support

? Check the features needed for your project:
 (*) Babel # Babel configuration
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support
 ( ) Router
 ( ) Vuex
 (*) CSS Pre-processors # CSS preprocessor
 ( ) Linter / Formatter
 (*) Unit Testing # Unit tests
 ( ) E2E Testing
Copy the code

Select the CSS preprocessor

? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):
> Sass/SCSS (with dart-sass) Fast, easy to install, and can be compiled into pure JavaScript code
  Sass/SCSS (with node-sass)
  Less
  Stylus
Copy the code

Select a unit test scenario

? Pick a unit testing solution:
> Mocha + Chai # UI test using Karma
  Jest
Copy the code

Directory structure and configuration

│ ├─ Public │ ├ ic.ico │ ├.html │ ├─ SRC │ ├.vue │ ├.js │ ├─ Public │ Favicon# Components for development| | button │ │ └ ─ button. Vue │ │ index, js# Entry to all components│ │ │ └ ─ styles# Public style│ _var. SCSS | icon. Js# iconfont js file| ─ tests# Unit tests| └ ─ unit | └ ─ button. The spec. Js │. Browserslistrc# Browser version compatibility Settings
│  .gitignore # ignore file
│  .babelrc Babel configuration file
│  package-lock.json
│  package.json
│  README.md 
Copy the code

Component library entry

src/packages/index.js

import Button from './button/button.vue';
/ /... Other components

// Globally register components
const install = Vue= > {
  Vue.component(Button.name, Button)
  / /... Other components
}

/** * It is possible for components to be introduced via script tags, such as  */
if (typeofWindow.Vue ! = ='undefined') {
  install(Vue) // The install method is invoked by default globally directly through script references
}

export default {
  install
}
Copy the code

Using components as plug-ins:

src/main.js

import zylUI from './packages';

Vue.use(zylUI)
Copy the code

Component development

Take the Button component as an example.

Learn from Element UI to implement basic usage of buttons, buttons with ICONS, load status buttons and other functions.

API design

parameter instructions type An optional value The default value
type type string primary / success / warning / danger / info default
icon Icon in the name of the class string
loading Loading status boolean false
position Icon in the location string left / right left

Global style

_var.scss

$primary: #409EFF;
$success: #67C23A;
$warning: #E6A23C;
$danger: #F56C6C;
$info: # 909399;

/ /... Other style

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
Copy the code

packages/button/button.vue

Basic structure:

Nested content in the form of slots

<template>
  <button class="zyl-button" :class="btnClass" :disabled="loading" @click="$emit('click', $event)">
    <! -- Short, other content -->
    <span v-if="this.$slots.default">
      <slot></slot>
    </span>
  </button>
</template>
Copy the code

Logic implementation

export default {
  name: 'zyl-button'.props: {
    type: {
      type: String.default: ' ',
      validator(type) { / / check
        if(type && ! ['warning'.'primary'.'info'.'success'.'danger'].includes(type)) {
          console.error('type The type is invalid! Must be: ' + ['warning'.'primary'.'info'.'success'.'danger'].join(', ') + 'One of them. ')}return true}},/ /... Other attributes
  },
  computed: { // Set button color according to type
    btnClass() {
      let classes = []
      if (this.type) {
        classes.push(`zyl-button-The ${this.type}`)}/ /... Other logic
      return classes
    }
  }
}
Copy the code

The style is set

@import '@/styles/_var.scss';

// ...

.zyl-button {
  border-radius: $border-radius;
  border: 1px solid $border-color;
  height: $height;
  font-size: $font-size;
  cursor: pointer;
  line-height: 1;
  padding: 12px 20px;
  display: inline-flex;
  justify-content: center;
  vertical-align: middle;
  user-select: none;

  // ...
  
  // Set the style of the button according to type
  @each $type.$color in (primary: $primary, success: $success, info: $info, warning: $warning, danger: $danger) # {{& -$type} {
      background-color: # {$color};
      border-color: # {$color};
      color: #fff;
      fill: #fff; }}/ /... Other Style Settings
Copy the code

Thus, a simple button component is developed. To ensure that our components are healthy and stable, we also need to add unit tests.

Setting up the Test Environment

We want to test the results of the UI rendered. You need to test it in a browser, in this case using Karma.

  • Install the Karma
npm install --save-dev @vue/test-utils karma karma-chrome-launcher karma-mocha karma-sourcemap-loader karma-spec-reporter karma-webpack mocha karma-chai
Copy the code
  • Configure the Karma file

karma.conf.js

const webpackConfig = require('@vue/cli-service/webpack.config');

module.exports = function(config) {
  config.set({
    frameworks: ['mocha'].// Set up the test framework
    files: ['tests/**/*.spec.js'].preprocessors: {
      '**/*.spec.js': ['webpack'.'sourcemap']},autoWatch: true.webpack: webpackConfig,
    reporters: ['spec'].browsers: ['ChromeHeadless'] // Headless browser})}Copy the code

package.json

{
  "scripts": {
    "test": "karma start"}}Copy the code

Writing unit tests

Using Button as an example, write unit tests.

import {shallowMount} from '@vue/test-utils'; // VUE provides a quick test method
import {expect} from 'chai';
import Button from '@/packages/button/button.vue';

// ...

describe('button.vue',()=>{
  it('1. Test whether button displays slot contents properly ', () = > {// Test the current component running in the browser
    const wrapper = shallowMount(Button, {
      slots: {default:'zyl-ui'}}); expect(wrapper.text()).to.eq('zyl-ui');
  })
  / /... Other test logic
})
Copy the code

Run the test task

npm run test
Copy the code

Component packaging

When all the component library run tests pass, our component is ready for use, and we can package the component library. Note that we can package in UMD, CommonJS or ES Module format.

  • Configuring packaging Commands

package.json

{
  "scripts": {
    "lib": "vue-cli-service build --target lib --name zyl-ui ./src/packages/index.js"}}Copy the code
  • Configure the Operation Portal

package.json

"main": "./dist/zyl-ui.umd.min.js"
Copy the code
  • Link the project to the global context

Execute in the zyl-UI project root directory

npm link
Copy the code

VuePress builds documents

VuePress is a VUUe-powered static web site generator. Support the use of Vue components in Markdown for simplicity and high performance. Of course, you can also use other document generators such as Docz, Storybook, etc.

According to the official documentation to learn how to use: www.vuepress.cn/guide/getti…

Project generation and configuration

  • The installation
mkdir zyl-docs && cd zyl-docs
npm init -y
npm install vuepress -D
Copy the code
  • The configuration scripts

package.json

{
    "docs:dev": "vuepress dev docs"."docs:build": "vuepress build docs"
}
Copy the code
  • Initialize the docs

Create a docs directory under the project root

├─ Docs │ ├─ Vuepress │ components# demo
|  |   styles # Document presentation style
|  |   config.js # configuration| | enhanceApp. Js │ │ │ ├ ─ components# Documentation for all components| | button. The md │ │ │ └ ─ README. Md | │. Gitignore# ignore file
│  package-lock.json
│  package.json
│  README.md 
Copy the code

docs/README.md

-- Home: true actionText: Welcome → actionLink: / Components/Button Features:- Title: Build your own component libraryBuild your own component library from 0 based on Vue2.6
Copy the code
  • Configuration navigation

docs/.vuepress/config.js

module.exports = {
  title: 'zyl-ui'.// Set the site title
  description: 'UI Component Library'./ / description
  dest: './build'.// Set the output directory
  port: 1234./ / port
  themeConfig: { // Theme configuration
    nav: [ // The header navigation bar
      {
        text: 'home'.link: '/'},].// Add a sidebar for the following routes
    sidebar: {
      '/components/': [{title: 'Basic'.collapsable: false.children: [
            'button'./ /... Other components]},// Other Settings]}}}Copy the code
  • Enhanceapp.js, an enhancement file for the client application

    This file is used to add the optimized configuration shown in the component Demo

    The installation

    npm install element-ui highlight.js node-sass sass-loader --save
    Copy the code

    Zyl – UI component library developed by Link

    npm link zyl-ui
    Copy the code

    .vuepress/enhanceApp.js

    import Vue from 'vue';
    import ElementUI from 'element-ui'; // Globally introduce element-ui
    import 'element-ui/lib/theme-chalk/index.css';
    
    import hljs from 'highlight.js'; // Code highlights
    import 'highlight.js/styles/googlecode.css';
    
    import zylUI from 'zyl-ui'; // To write the corresponding document package
    import 'zyl-ui/dist/zyl-ui.css';
    // Global register directive
    Vue.directive('highlight'.function (el) {
      let blocks = el.querySelectorAll('pre code');
      blocks.forEach((block) = >{
        hljs.highlightBlock(block)
      })
    })
    export default ({
      Vue
    }) => {
      Vue.use(ElementUI);
      Vue.use(zylUI)
    }
    Copy the code

The styles/palette. Styl file is used to override the default styles of vuepress, while components/ demo-blocker. Vue file is mainly a rewrite of the styles shown by the default theme demo and some definition of the display logic. The code is too long; I won’t repeat it here.

Write Markdown files for the corresponding components

For the button component example, create a button.md file under docs/ Components

# Button ButtonCommon operation buttons## Basic usageBasic button usage<demo-block>
:::slot source
<button-test1></button-test1>::: Uses the type attribute to define the style of the Button :::slot highlight (HTML) 
      
< yl-button> default button < yl-button type="primary"> Main button < yl-button < zyl - button type = "danger" > dangerous button < / zyl - button > < / div > (` ` `) : : : < / demo - block > / / slightly
Copy the code

Visit http://localhost:1234 to see the documentation. Of course, you can deploy documents to your own server, or to Github Pages, without expanding here.

Publish components to NPM

  • configuration.npmignorefile
src
public
tests
Copy the code
  • release

You need to make sure these fields are in package.json before publishing.

  1. name

It is the name of the package published to NPM and installed. Please ensure that it is unique, you can go to the NPM first search, whether it already exists.

  1. version

Version number, following semantic versioning rules. Changes are made with each new release. You can use the NPM version [major.minor.patch] command to perform the update.

  1. main

It’s the entrance to the bag.

npm addUser If you don't have a username, register one, otherwise log in directly
npm login Log in and enter your password
npm publish # publish, execute in zyl- UI root directory
Copy the code

After a while, you can go to NPM and search for your published packages. Next you can NPM install zyl-UI to install and use your own component libraries.

conclusion

This paper mainly introduces the process of building UI component library based on Vue and building documents based on VuePress. Involves the organization of the project, component development process, unit testing, packaging, documentation, release and so on.