Most of the time we don’t need to build our own wheels, but there may be special cases where we want to have custom UI components. Here I make a basic Button component with VUE and publish it to NPM, then try using the UI component.

Need to pre –

  • vue-cl3
  • NPM account password
npm install -g @vue/cli
# OR
yarn global add @vue/cli
Copy the code

Create a project

Run the vue curete bkyz-UI Manually select features command

 (*) Babel
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support
 ( ) Router
 ( ) Vuex
 (*) CSS Pre-processors
 (*) Linter / Formatter
 ( ) Unit Testing
 ( ) E2E Testing
Copy the code

Press space to select, enter to enter the next step.

Of the remaining options, my choice is:

Code style — ESLint + Standard Config format detection — Lint on Save Configuration file generation — In package.json Whether to Save preconfiguration — No

Configuration depends on personal preference, then press Enter to generate a complete project.

Create a packages directory in the root directory to hold the UI components we want to develop; Create a local directory in the root directory to test the effect of referencing our own UI components. Since we changed the directory structure of the original project, the corresponding directory could not be found for the local operation and packaging of the system. Therefore, we need to create a vue.config.js folder in the root directory of the project to manually modify the Webpack configuration and make the local operation and packaging of the system normal.

// vue.config.js const path = require('path'); module.exports = { pages: { index: { entry: 'local/main.js', template: 'public/index.html', filename: 'index.html' } }, chainWebpack: config => { config.module .rule('js') .include.add(path.resolve(__dirname, 'packages')).end() .use('babel') .loader('babel-loader') .tap(options => { return options; }}})Copy the code

Production of components

Create two new folders, Button, Fonts and an index.js file in the Packages folder. Edit packages/index. Js

// packages/index.js import Button from './ Button 'import './fonts/ font-scss' // store component list const Components = [Button] // Define the install method that accepts Vue as an argument. If you use use to register your plug-in, Const install = function (Vue) {forEach(component => {Vue.component(component.name, Component)})} // Check whether the file is imported directly if (typeof window! == 'undefined' && window.vue) {install(window.vue)} export default {// The exported object must have install, Use () method to install, Button}Copy the code

Create index.js in the button folder to export the component

Import Button from './ SRC /button.vue' Install = function (Vue) {Vue.component(button.name, Button)} export default ButtonCopy the code

Edit packages/button/SRC/button. Vue

<template> <button class="mc-button"> <! <span v-if="$slots.default"><slot></slot></span> </button> </template> export default {name: 'McButton', props: {} }Copy the code

Then create a new SRC folder and put the Button component, which is just a normal Vue file and will continue to add properties to improve the component.

button type

The common types are: primary/SUCCESS/warning/danger/info/text

We use an array of dynamically typed bindings

<template> <button class="mc-button" :class="[ `mc-button--${type}` ]"> ... </button> </template> <script> export default { ... props: { type: { type: String, default: 'default' } } } </script> <style lang="scss'> .mc-button { display: inline-block; line-height: 1; white-space: nowrap; cursor: pointer; background: #fff; border: 1px solid #dcdfe6; color: #606266; -webkit-appearance: none; text-align: center; box-sizing: border-box; outline: none; margin: 0; The transition: 0.1 s; font-weight: 500; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; padding: 12px 20px; font-size: 14px; border-radius: 4px; &:hover, &:focus { color: #409eff; border-color: #c6e2ff; background-color: #ecf5ff; } &--primary {} &--success {} &--warning {} &--info {} &--danger {} } </style>Copy the code

This enables different types of button styles

Add rounded corners

<button 
    class="mc-button" 
    :class="[
      `mc-button--${type}`,
      {
            ...
            'is-round': round
       }
    ]">
    ...
</button>

Copy the code

Add a round parameter, which is skipped here, and add a rounded corner

&.is-round {
    border-radius: 20px;
    padding: 12px 23px;
 }

Copy the code

Similarly, circular buttons can be implemented, whether to disable, add ICONS, I will not write in detail here.

<template> <button class="mc-button" :disabled="disabled" @click="handleClick" :class="[ `mc-button--${type}`, { 'is-plain': plain, 'is-round': round, 'is-circle': circle, 'is-disabled': disabled } ]"> <i :class="icon" v-if="icon"></i> <! <span v-if="$slots.default"><slot></slot></span> </button> </template>Copy the code

Run the project

Now run local and see what happens. Improve the previous local folder content, add app. vue, man.js, testButton. vue three files. App.vue takes the McButton component from testButton and shows it

// local/App.vue
<template>
  <div id="app">
    <test-buttons></test-buttons>
  </div>
</template>

<script>
import TestButtons from './TestButton'
export default {
  name: 'app',
  components: {
    TestButtons
  }
}
</script>

<style lang="scss">
</style>
Copy the code

Main.js is the entry file

// local/main.js import Vue from 'Vue' import App from './ app. Vue 'import BkyzUI from '.. /packages' Vue.config.productionTip = false Vue.use(BkyzUI) new Vue({ render: h => h(App) }).$mount('#app')Copy the code

With the introduction of packages component libraries, TestButton.vue can use Mc-button directly

<template> <div class="app"> <div class="row"> < Mc-button type="primary"> </ Mc-button > < Mc-button type="success"> < Mc-button type="info"> </ Mc-button > < Mc-button type="warning"> / /... </div> </div> </template> <script> export default { name: 'TestButtons' methods: { } } </script> <style lang="scss" scoped> .app { width: 600px; height: 200px; display: flex; flex-direction: column; justify-content: center; align-items: center; margin-top: 100px; } .row { padding: 10px 0; } .mc-button { margin-left: 10px; } </style>Copy the code

After executing NPM Run serve, open the page and you can see that the external custom components are available in the project.

packaging

In the official documentation of VUE-CLI3 there is a build objective that clearly states how to package it as an application or a library! At this point, we need to add a package command to package.json

Vue-cli-service build --target lib Specifies the package fileCopy the code

The console then executes yarn Lib to package the external component libraries, including font ICONS, to create a dist folder.

Since we develop component libraries for others to use, we don’t have to publish all of our code to NPM. So we need to create a.npmignore file in the root directory of the project and ignore those file uploads

//.npmignore # ignores directory local/ packages/ public/ # ignores the specified file vue.config.js babel.config.js *.map.editorconfig.jsCopy the code

Edit package.json and add main to make it easier for others to find the packaged file when downloading it

{
 "main": "dist/bkyz-ui.umd.min.js",
 ...
}
Copy the code

My Git repository click

Note:

  • When uploading to NPM, change the private property in package.json to false
  • During package iteration, modify the version number in package.json before executing the publish command

Published to the NPM

Note: because we want to upload NPM, so the local NPM source should use the original source, not taobao source or other sources

NPM config get registry / / view the NPM mirror current source NPM config set registry / / set to NPM source at https://registry.npmjs.org/Copy the code

Execute NPM login on the console and NPM publish after login. Publish.

Use our custom component library

Once published, you can try it out. Again, try vue’s Web project here. Create a new vue101 project, skip the process, and reference it in main.js

import Vue from 'vue'
import App from './App.vue'
import BkyzUI from 'bkyz-ui'
Vue.config.productionTip = false
Vue.use(BkyzUI)
new Vue({
  render: h => h(App),
}).$mount('#app')

Copy the code

Modify the helloWorld.vue file

<template> <div class="hello"> < Mc-button plain @click="handleClick"> font </ Mc-button > < Mc-button </ button> < Mc-button icon=" Mc-icon-check "circle plain type="primary"></ Mc-button ></ div> </template> <script> import 'bkyz-ui/dist/bkyz-ui.css' import Bkyz from 'bkyz-ui' export default { name: 'HelloWorld', methods: { handleClick() { console.log('click'); } }, props: { msg: String } } </script>Copy the code

If it is quoted on demand:

<template> <div class="hello"> < Mc-button plain @click="handleClick"> font </ Mc-button > < Mc-button </ button> < Mc-button icon=" Mc-icon-check "circle plain type="primary"></ Mc-button ></ div> </template> <script> import 'bkyz-ui/dist/bkyz-ui.css' import Bkyz from 'bkyz-ui' export default { name: 'HelloWorld', components: { McButton: Bkyz.Button }, methods: { handleClick() { console.log('click'); } }, props: { msg: String } } </script>Copy the code

Take a look at the page

reference

  • Build your own UI framework from scratch – publish to NPM
  • Vue components publish NPM best practices