current position:Home>How to develop UI component library (heavy UI) based on Vue

How to develop UI component library (heavy UI) based on Vue

2022-05-15 04:57:30Hu Jinbin

front ⾔

Vue yes ⼀ set ⽤ Yu Jian ⽤ Household sector ⾯ The progressive framework of ,⽬ More and more developers are learning and making ⽤.⽽ Component library can help us save development time ⼒,⽆ Need all East ⻄ Start from scratch , adopt ⼀ all ⼩ The components are spliced together , We get what we want in the end ⻚⾯. stay ⽇ Often, if there is no specific ⼀ Some business needs , send ⽤ Component library into ⾏ Development ⽆ Doubt is more convenient ⾼ effect ,⽽ And the quality is relatively better ⾼ Of ⽅ case .

Ben ⽂ Describes how to base on vue⼀ Step by step ⼀ individual UI Creation of component library .

Component library Officer ⽹

github Address

npm Address

⼀、 Technology stack

Let's briefly understand ⼀ Next, we need to build ⼀ individual UI Component library , What technology stacks will be involved , Next ⾯ I chose ⽤ The content of :

  1. vue-cli: Officer, ⽅⽀ Hold on to CLI foot ⼿ frame , Provide ⼀ A modern build setup with zero configuration ;
  2. Vue: Progressive type JavaScript library ;
  3. Jest:JavaScript The test framework ,⽤ Unit testing in component library ;

⼆、 Component development

term ⽬ initialization

Start , Need to create ⼀ An empty one vue term ⽬, On this basis, we can start to write the next component library !

npm i -g vue-cli // yarn add global vue-cli
vue init webpack heaven-ui  //(heaven-ui) You can change it to your name at will 
cd heaven-ui
npm run dev

We install the dependency and go to ⼊ term ⽬ After starting the service vue-cli3 Meeting ⾃ Move to show us ⼀ A default ⻚⾯, this ⾥ I make ⽤sass,⽤ To beautify ui Style of component .

⽬ Recording structure

This is my ⽬ Recording structure and interpretation

|- build/ # webpack Packaging configuration  
|- lib/ #  Package the generated files here  
|- src/ #  Write the code here  
    |- components/ #  Components , Each component is a subdirectory  
    |- mixins/ #  Reuse of mixin 
    |- utils #  Tool catalog  
    |- App.vue #  Development preview running locally 
    |- index.js #  Packing entrance , Export of components  
    |- main.js #  Run locally 
|- static/ #  Store some additional resource files , Pictures and the like  
|- test/ #  Test folder  
    |- specs/ #  Store all test cases  
    |- jest.conf.js/ # jest Unit test configuration  
|- .npmignore 
|- .gitignore 
|- .babelrc 
|- README.md 
|- package.json

Component library structure

expose ⼀ Of all components ⼊⼝, The detailed code of the component only shows button part

src/components/index.js

import Alert from './components/alert/index.js'
import Button from './components/button/index.js'
import ButtonGroup from './components/button-group/index.js'
import Checkbox from './components/checkbox/index.js'
import CheckboxGroup from './components/checkbox-group/index.js'
import DatePicker from './components/date-picker/index.js'
import Form from './components/form/index.js'
import FormItem from './components/form-item/index.js'
import Icon from './components/icon/index.js'
import Input from './components/input/index.js'
import Option from './components/option/index.js'
import Pagination from './components/pagination/index.js'
import Radio from './components/radio/index.js'
import RadioGroup from './components/radio-group/index.js'
import Rate from './components/rate/index.js'
import Select from './components/select/index.js'
import Switch from './components/switch/index.js'
import Table from './components/table/index.js'
import HTableColumn from './components/table-column/index.js'
import Tag from './components/tag/index.js'


const components = [
    Button,
    ButtonGroup,
    Checkbox,
    CheckboxGroup,
    DatePicker,
    Form,
    FormItem,
    Icon,
    Input,
    Option,
    Pagination,
    Radio,
    RadioGroup,
    Rate,
    Select,
    Switch,
    Table,
    HTableColumn,
    Tag,
  ]
  
  const install = function(Vue, opts = {}) {
    components.map(component => {
      Vue.component(component.name, component);
    })
    Vue.prototype.$alert = Alert;
  }

/*  Support the use of tags to introduce  */
if (typeof window !== 'undefined' && window.Vue) {
   install(window.Vue);
}

export default {
    install,
    Alert,
    Button,
    ButtonGroup,
    Checkbox,
    CheckboxGroup,
    DatePicker,
    Form,
    FormItem,
    Icon,
    Input,
    Option,
    Pagination,
    Radio,
    RadioGroup,
    Rate,
    Select,
    Switch,
    Table,
    HTableColumn,
    Tag,
}

src/components/button/index.js

import HButton from './src/button';

HButton.install = function(Vue) {
  Vue.component(HButton.name, HButton);
};

export default HButton;

Component part ⼤ It's all like this ⼦ 了

img

Packaging configuration

⽬ The recording is finished , Then you should fill ⾎⾁ 了 , To pack ⼀ A component library item ⽬, We have to configure our webpack, Otherwise write the source code can not run up . So let's start with build⽬ Record

webpack.base.js . Store basic ⼀ some rules To configure

webpack.prod.js . Packaging configuration of the entire component library

build/webpack.base.conf.js

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: process.env.NODE_ENV === 'production' ? './src/index.js' : './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
      'untils': resolve('src/untils'),
    }
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.scss$/,
        loaders:['style','css','sass']
      }
    ]
  },
  node: {
    // prevent webpack from injecting useless setImmediate polyfill because Vue
    // source contains it (although only uses it if it's native).
    setImmediate: false,
    // prevent webpack from injecting mocks to Node native modules
    // that does not make sense for the client
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  }
}

build/webpack.prod.conf.js

'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

const env = require('../config/prod.env')

const webpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true,
      usePostCSS: true
    })
  },
  devtool: config.build.productionSourceMap ? config.build.devtool : false,
  output: {
    path: config.build.assetsRoot,
    filename: 'heaven-ui.min.js',
    library: 'heaven-ui',
    libraryTarget: 'umd'
  },
  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      'process.env': env
    }),
    new UglifyJsPlugin({
      uglifyOptions: {
        compress: {
          warnings: false
        }
      },
      sourceMap: config.build.productionSourceMap,
      parallel: true
    }),
    // extract css into its own file
    new ExtractTextPlugin({
      filename: 'heaven-ui.min.css',
    }),
    // Compress extracted CSS. We are using this plugin so that possible
    // duplicated CSS from different components can be deduped.
    new OptimizeCSSPlugin()
  ]
})

if (config.build.productionGzip) {
  const CompressionWebpackPlugin = require('compression-webpack-plugin')

  webpackConfig.plugins.push(
    new CompressionWebpackPlugin({
      asset: '[path].gz[query]',
      algorithm: 'gzip',
      test: new RegExp(
        '\\.(' +
        config.build.productionGzipExtensions.join('|') +
        ')$'
      ),
      threshold: 10240,
      minRatio: 0.8
    })
  )
}

if (config.build.bundleAnalyzerReport) {
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig

this ⾥ The output I configured ⽬ Recorded as lib, The result after packaging is shown in the figure below :

3、 ... and 、 unit testing

Unit testing has the following advantages :

\1. May detect hidden features bug

\2. Ensure the security of code refactoring .

Each component in the component library ⼀ Both components may refactor or update iterations , If unit test coverage ⾼ Words , The more likely you are to find a potential problem after modifying the code .⽐ If the version is upgraded , Lead to the loss of some function .

After the development and debugging of component library is completed , We need to write unit tests for each component , In order to achieve 100% The coverage rate is ⽬ mark .

With button For example :

test/specs/Button.spec.js

import Vue from 'vue'
import Button from '@/components/button'

describe('button.vue', () => {
  it('button Whether there is ',()=>{
    expect(Button).to.be.ok;
  })
})

this ⾥ The output I configured ⽬ Recorded as lib

Four 、 Release NPM

Release npm Before , We must comply with npm To write our package.json, Let's solve the problem of component library packaging first ,⾸ First we need to let our feet ⼿ Compile our component code , And output to the specified ⽬ Record , We are in accordance with the contract specification ⼀ Generally, it will be output to lib⽬ Record . term ⽬ After packing , We need to write package⽂ Piece description,keywords etc. , The details are as follows :

description Description of component library ⽂ Ben

keywords Key words of component library

license license agreement

repository The component library is associated with git Warehouse address

homepage The component library shows ⾸⻚ Address

main The main of the component library ⼊⼝ Address ( Making ⽤ When the component is installed, it will lead to ⼊ The address of )

private Declare the privacy of the component library , If you want to publish to npm Male ⽹ On , You need to delete this property or set it to false

publishConfig ⽤ To set up npm Address of publication , This configuration serves as an internal npm For the server ⾮ Often the key is , Can be set as private npm Warehouse

Publish to npm Of ⽅ The method is also very simple , ⾸ First, we need to register to npm Officer, ⽹ register ⼀ Accounts , Then log in to the console , Finally, we hold ⾏npm publish namely

can . The specific process is as follows :

//  Sign in 
npm login
//  Release 
npm publish
//  If the publishing fails, the permission problem will be prompted , Please execute the following order 
npm publish --access public

Be careful : This time publish The version number needs to be modified

5、 ... and 、 summary

We can ⽤vue-cli Or others ⼯ With another ⽣ become ⼀ individual demo term ⽬,⽤ This item ⽬ To quote ⼊ Our component library . If your package hasn't been released yet , Can be in your

Component library item ⽬⽬ Record ⽤ npm link perhaps yarn link To create ⼀ individual link

And then in your demo⽬ Record the envoy ⽤ npm link package_name perhaps yarn link package_name this ⾥ Of package_name It's your component library

Package name , And then in your demo term ⽬ Of ⼊⼝⽂ Pieces of ⾥

import Vue from vue
import Heaven from 'heaven-ui'
import 'heaven-ui/dist/heaven-ui.min.css'// 
 Other code  ...

Vue.use(Heaven)

After setting this up , The components we create can be in this item ⽬⾥ send ⽤ 了

Link to the original text :https://www.leheavengame.com/article/60a89b56f631d777dcde0367

copyright notice
author[Hu Jinbin],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2022/135/202205142214316476.html

Random recommended