Preface 🍊
There are a variety of UI component libraries on the market, and their power is undeniable. But sometimes it is necessary to develop a custom component library for your own team. Sometimes the original components can’t meet our various needs, so we need to modify the original components.
So the purpose of this article is to let readers through this article, small can do a simple plug-in for people to use, big can architecture and maintenance of a component library is not at all. Welcome to give directions, you can also welcome the comments below.
Technology stack 🍊
- Vue-cli3 basic creation and packaging tips
- The basic syntax of VUE
- The release of the NPM
Complete project directory structure 🍊
Vase - UI ├ ─. Eslintrc. Js ├ ─. Gitignore ├ ─. Npmignore ├ ─ Babel. Config. Js ├ ─ the deploy. Sh ├ ─ docs / / vuepress development │ ├ ─ │ ├─ ├─ ├─ ├─ ├─ vs-home. Vue │ ├─ config.js // Vurepess entrance configuration changes, including the sidebar on the left, upper right nav navigation menu │ │ └ ─ dist/pack/vuepress │ │ ├ ─ 404 HTML │ │ ├ ─ assets │ │ │ ├ ─ CSS │ │ │ ├ ─ │ ├─ ├─ ├─ 0 ├─ ├─ 0, ├─ 0, ├─ 0 Markdown │ ├─ ├─ ├─ basic │ │ ├─ ├─ │ ├─ get-started The HTML │ ├ ─ README. Md │ └ ─ views │ ├ ─ components │ │ └ ─ basic │ │ └ ─ README. Md │ └ ─ guide │ ├ ─ the get - started. Md │ └ ─ Install.md ├─ Package-Lock. json ├─ Package. json // │ ├─ ├─ SRC │ ├─ ├─ ├─ ├─ vue │ ├─ fonts │ ├─ font ├─ ├─ element.txt // ├─ element.txt // ├─ element.txt // Keep-alive │ ├─ ├─ public // │ ├─ ├─ class │ ├─ favicon │ ├─ favicon.ico │ ├─ class │ ├─ vue │ ├─ class │ ├─ favicon │ ├─ favicon ├ ─ button. Which s │ ├ ─ component, which s │ ├ ─ index, which s │ └ ─ vase - UI. Which s ├ ─ vue. Config. Js └ ─ yarn. The lockCopy the code
Project Planning 🍊
Create a default project using commands in the specified directory, or choose your own.
Create a project
Just name the project whatever makes sense to you
$ vue create vase-ui
Note: Since we are developing a third-party dependency library, we chose Manually select Features.
Select which features need to be installed in the project
(*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
( ) Router
( ) Vuex
(*) CSS Pre-processors
(*) Linter / Formatter
( ) Unit Testing
( ) E2E Testing
Copy the code
The copied code system includes the basic Babel + ESLint setting by default, we just need to choose the CSS configuration. Move the up and down keys on the keyboard to select a feature and press the space bar
Which CSS preprocessor language to install
Sass/SCSS (with dart-sass)
Sass/SCSS (with node-sass)
Less
Stylus
Copy the code
Because the style in Element’S UI is Sass, we can just choose the first option. Why not choose the second option? Dart-sass is easier to download than Node-sass
Selecting a code Style
ESLint with error prevention only
ESLint + Airbnb config
ESLint + Standard config
ESLint + Prettier
Copy the code
Generally, ESLint + Prettier is used
That way to do code formatting
(*) Lint on save
( ) Lint and fix on commit
Copy the code
Copy code select Ctrl+S to check the code format when saving
Configuration file generation mode
In dedicated config files
In package.json
Copy the code
Depending on personal preference, I’ll take the first option
Whether to save the preconfiguration
Save this as a preset for future projects? (y/N)
Copy the code
Copy the code and see what the project needs, so I’m going to choose N. When we press Enter, the system will automatically integrate the selected configuration into the template for us, and then generate a complete project.
Adjust the directory
Here we refer to element’s directory structure
Delete the SRC and assets directories and create one in the root directorypackages
The directory is for the UI components we are developing; Create a test directory in the root directory to test our own UI components (no longer needed after the introduction of Vuepress).
| - packages / / change the original SRC directory to packages for writing storage componentCopy the code
Added packages directory that was not added to webpack compilation
Note: Cli3 provides an optional vue.config.js configuration file. If this file exists, it will be automatically loaded, and all the configuration for the project and webpack will be in this file.
Note: Vue’s package folder uses Monorepo: Monorepo is a code management mode that puts multiple packages in a single REPO, rather than the traditional multiple packages and multiple repOs. About monorepo can understand in this article https://juejin.cn/post/6844903961896435720
Webpack configuration modified
Packages is a new directory that is not handled by WebPack by default, so you need to add configuration support for this directory.
ChainWebpack is a function that takes an instance of a ChainableConfig based on webpack-chain. Allows for more fine-grained changes to the internal WebPack configuration. Create the vue.config.js file in the root directory and do the following:
// Change SRC to test
const path = require("path");
module.exports = {
pages: {
index: {
entry: "test/main.js". template: "public/index.html". filename: "index.html" } }, // Extend webpack configuration to include Packages in compilation 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
Component writing 🍊
The button component
- in
packages
Directory, where all individual components are stored as folders, so create a directory herebutton
- in
button
Directory creationsrc
Directory stores component source code - in
button
Directory creationindex.js
The file provides references to components externally. - create
fonts
Folder function is to storeelement
Some basic styles of
/packages/button/src/button.vue
The core component code is as follows (the style code is not posted here, but can be found in the code repository) :
<template>
<button
class="vs-button"
:disabled="disabled" @click="handleClick" :class="[ type ? `vs-button--${type}` : '', buttonSize ? `vs-button--${buttonSize}` : '', { 'is-plain': plain, 'is-round': round, 'is-circle': circle, 'is-disabled': disabled } ]. "" > <i :class="icon" v-if="icon"></i> <! -- if no incoming slot is displayed --> <span v-if="$slots.default"><slot></slot></span> </button> </template> <script> export default { name: "VsButton". props: { size: String. type: { type: String. default: "default" }, plain: { type: Boolean. default: false }, round: { type: Boolean. default: false }, circle: { type: Boolean. default: false }, disabled: { type: Boolean. default: false }, icon: { type: String. default: "" } }, methods: { handleClick(e) { this.$emit("click", e); } } }; </script> <style lang="scss"> </style> Copy the code
- Modify the
/packages/button/index.js
Documents for external reference:
import VsButton from "./src/button.vue";
// Provide the install installation method for components to be imported on demand
VsButton.install = function(Vue) {
Vue.component(VsButton.name, VsButton);
};
export default VsButton; Copy the code
Keep alive – components
Introduction: This component is a simple stack implementation of Vue forward refresh backward without refresh
- in
packages
Directory creationkeep-alive
- in
keep-alive
Directory creationindex.js
The file uses the functional component in it and provides references to the component externally.
- The complete code is as follows:
import Vue from "vue";
let cacheKey = "cacheTo";
let $router = { beforeEach: (a)= >{}};// The vue. observable handle makes the component's store pluggable
const state = Vue.observable({ caches: [] }); const clearCache = (a)= > { if (state.caches.length > 0) { state.caches = []; } }; const addCache = name= > state.caches.push(name); const beforeEach = (a)= > { $router.beforeEach((to, from, next) = > { // 1. None of these are class list pages // Clear the cache // 2. Both are class list pages // If 'to' is not in 'from' configuration, clear the cache and add 'to' cache // Keep the cache of 'from' and add the cache of 'to' // 3. The new route is the class list page // If 'from' is not in 'to' configuration, clear the cache and add 'to' cache // Otherwise, no action is required // 4. Old routes are class list pages // If 'to' is not in 'from' configuration, clear the cache const toName = to.name; const toCacheTo = (to.meta || {})[cacheKey]; const isToPageLikeList = toCacheTo && toCacheTo.length > 0; const fromName = from.name; const fromCacheTo = (from.meta || {})[cacheKey]; const isFromPageLikeList = fromCacheTo && fromCacheTo.length > 0; if(! isToPageLikeList && ! isFromPageLikeList) { clearCache(); } else if (isToPageLikeList && isFromPageLikeList) { if (fromCacheTo.indexOf(toName) === - 1) { clearCache(); } addCache(toName); } else if (isToPageLikeList) { if (toCacheTo.indexOf(fromName) === - 1) { clearCache(); addCache(toName); } } else if (isFromPageLikeList) { if (fromCacheTo.indexOf(toName) === - 1) { clearCache(); } } next(); }); }; const VsKeepAlive = { install(Vue, options = { key: "".router: ""{}) const { key = "cacheTo", router } = options; if (key) { cacheKey = key; $router = router; beforeEach(); } const component = { name: "VsKeepAlive". functional: true. render(h, { children }) { return h("keep-alive", { props: { include: state.caches } }, children); } }; Vue.component("VsKeepAlive", component); } }; export default VsKeepAlive; Copy the code
Precautions for use:
- The route configuration must include the name attribute, and the name must be the same as the component name
- The cacheTo priority is smaller than keepAlive, so pages that handle this need do not set keepAlive
- It is possible to set up two pages before caching only when switching between them, but I haven’t found a scenario that works
Export components
- Integrate all components, export, that is, a complete component library changes
/packages/index.js
File to export the entire component library:
import Button from "./button";
import KeepAlive from "./keep-alive";
import "./fonts/font.scss";
// Store a list of components
const components = [Button]; // Define the install method that accepts Vue as an argument. If the plug-in is registered with use, all components will be registered const install = function(Vue, options = { key: "", router: {} }) { const { key = "cacheTo", router } = options; // Iterate over registered global components components.forEach(function(item) { if (item.install) { Vue.use(item); } else if (item.name) { Vue.component(item.name, item); } }); Vue.use(KeepAlive, { key, router }); }; // Check whether the file is imported directly if (typeof window! = ="undefined" && window.Vue) { install(window.Vue); } export { Button, KeepAlive }; export default { // Exported objects must have install to be installed by vue.use () version: "0.3.4". install }; Copy the code
Note: If we want to use our keep-alive component, we need to pass in the Router parameter during registration.
Here we can see how Element defines this block:
NPM release 🍊
package.json
In thescript
Add a new command to compile to the library, and then use itnpm run lib
Command to pack
"scripts": {
"lib": "vue-cli-service build --target lib --name vase-ui --dest lib packages/index.js"
},
Copy the code
Note:
--target
: Build target, default to application mode. Here change to lib to enable library mode.dest
: Output directory, default dist. So let’s change this to lib[entry]
: The last parameter is the entry file, which defaults to SRC/app.vue. Here we specify compile packages/ component library directory
- Execute the compile library command
npm run lib
- configuration
package.json
File published tonpm
The field of
- Name: package name, which is unique. Search for the name on the NPM website, or change the name if it exists.
- Version: indicates the version number. The version number must be changed each time you release data to NPM. The version number cannot be the same as the historical version number.
- Description: description.
- Main: entry file, this field should point to our final compiled package file.
- Keyword: Separates the final word that you want the user to search for with Spaces.
- Author: the author
- Private: indicates whether to publish to NPM. Change the value to false
- License: Open source agreement
- You want to package the generation file of the library
- Browserslist: Specifies the scope of the target browser for the project
- Repository: Specifies the location of the code. This is very helpful for people who want to contribute. If your Git repo is on GitHub, the NPM docs command will be able to find you.
Here are my reference Settings
{
"name": "vase-ui". "version": "0.3.4". "description": "A Component Library for Vue.js.". "private": false. "main": "lib/vase-ui.common.js". "files": [ "lib". "src". "packages". "types" ]. "repository": { "type": "git". "url": "[email protected]:JohnYu588/vase-ui.git" }, "author": "yzx". "license": "MIT". "browserslist": [ "1%" >. "last 2 versions" ] } Copy the code
- Add the.npmignore file to ignore the publishing file
# ignore directorytest/
packages/
public/
docs/
node_modules/ # ignore the specified filevue.config.js babel.config.js *.map .editorconfig.js Copy the code
- Release NPM
- Go to the NPM website and register an account
- perform
npm login
Enter your account and password to log in - perform
npm publish
upload - Wait a few minutes after the successful release
NPM's official website
To search. The following is just submitted
Pay attention to
- Be sure to add main to the scripts of package.json so that others can find the packaged files when downloading them
- When uploading to NPM, change the private property value in package.json to false
- Be sure to change the project version number when you publish modified source code to NPM
Official website production 🍊
Using the vue press
- Used in the original project
# install dependencies
npm install -D vuepress
Create a docs directory
mkdir docs
Copy the code
- in
package.json
To configure the script
"scripts": {
"docs:dev": "vuepress dev docs". "docs:build": "vuepress build docs"
},
Copy the code
- Simple configuration in
docs/.vuepress
New fileconfig.js
module.exports = {
base: '/vase-ui/'. title: 'Vase UI'. description: 'Inspiration from heian vase'. head: [['link', { rel: 'icon'.href: '/favicon.ico' }]],
themeConfig: { nav: [ { text: 'Home'.link: '/' }, { text: 'Github'.link: 'https://github.com/JohnYu588/vase-ui/' }, ]. sidebar: [ { title: 'Development Guide'. collapsable: true. children: ['views/guide/install.md'.'views/guide/get-started.md']. }, { title: 'components'. collapsable: true. children: ['views/components/basic/']. }, ]. }, }; Copy the code
- Use vUE components
Vue files found in.vuepress/ Components are automatically registered as global asynchronous components. Can be referenced in the markdown, we can write here to show case the vue file code in the highlight what I use be a vue – highlightjs: in the/docs /. Vuepress/components/create button vs. – botton. Vue file code is as follows:
<template>
<div>
<h3>Basic usage</h3>
<vs-button>default</vs-button>
<vs-button type="primary">primary</vs-button> <vs-button type="info">info</vs-button> <vs-button type="success">success</vs-button> <vs-button type="warning">warning</vs-button> <vs-button type="danger">danger</vs-button> <pre v-highlightjs><code class="vue">{{code1}}</code></pre> </div> </template> <script> import btn from '.. /.. /.. /packages/button/src/button';import Vue from 'vue' import VueHighlightJS from 'vue-highlightjs'; Vue.use(VueHighlightJS); export default {data() { return { code1: ` <vs-button>default</vs-button> <vs-button type="primary">primary</vs-button> ` .replace(/^\s*/gm, '') .trim(), code2: ` <s-button disabled type="primary">disabled</s-button> ` .replace(/^\s*/gm, '') .trim(), code3: ` <s-button icon="home" type="primary">home</s-button> <s-button icon="phone-fill" type="primary" icon-position="right">call</s-button> <s-button icon="visible" type="primary">show password</s-button> ` .replace(/^\s*/gm, '') .trim(), code4: ` <s-button loading icon="download" type="primary">In the load</s-button> ` .replace(/^\s*/gm, '') .trim(), code5: ` <s-button-group> <s-button icon="left" icon-position="left">prev</s-button> <s-button>middle</s-button> <s-button icon="right" icon-position="right">next</s-button> </s-button-group> ` .replace(/^ {8}/gm, '') .trim(), }; }, components: { 'vs-button': btn, }, }; </script> // Styles are not posted here <style lang="scss" scoped></style> Copy the code
- Written document
Since all pages need to be rendered by the Node.js server to generate static HTML, for components that are less SSR friendly (such as those that contain custom instructions), you can wrap them in the built-in ClientOnly component. Also note that because it is SSR, the component internal beforeCreate, created lifecycle hook functions do not access the browser/DOM API and can only be called in beforeMount and Mounted.
/ docs/views/components/basic created under the README, md:
---
title: 'the Basic basis'
sidebarDepth: 2
---
# # Button Button <ClientOnly> <vs-button/> <font size=5>Attributes</font> | parameters | | | | | alternatives, a default value| : -- -- -- -- -- - | -- - | -- - | -- -- -- -- -- - | -- - || type | | button type string | primary, info, success, warning, danger | - || disabled button if disable | | Boolean | - |false | | icon name | | button icon string | - | - || icon - position | | icon around the button's position string | left and right | - || loading | displayed loading icon | Boolean | - |false | </ClientOnly> Copy the code
Note: Refer to the documentation above for creating the installation help and start page in the Guide directory (see git for details).
- Deployment to making
It’s very clear on the website. Click here. Sh is added in the root directory of the project and run the./deploy.sh command in Windows to publish the project to Github Pages.
deploy.sh:
#! /usr/bin/env sh
Make sure the script throws any errors it encounters
set -e
Generate static files npm run docs:build Go to the generated folder cd docs/.vuepress/dist # if publish to custom domain name # echo 'www.example.com' > CNAME git init git add -A git commit -m 'deploy' # if posted to https://
.github
# git push -f [email protected]:<USERNAME>/<USERNAME>.github.io.git master Github. IO /
git push -f [email protected]:JohnYu588/vase-ui.git master:gh-pages cd - Copy the code
- Preview the execution
yarn docs:dev
Command preview official website:
After the upload at https://johnyu588.github.io/vase-ui/ can see directly
Use the newly released component library 🍊
npm install vase-ui -S
Copy the code
- References can be introduced in a project’s main.js in two ways
- Global registration
import VaseUI from "vase-ui";
Vue.use(VaseUI, { router });
Copy the code
- According to the need to introduce
import { Button, KeepAlive } from "vase-ui";
Vue.use(Button)
.use(KeepAlive, { router });
Copy the code
- use
<vs-button icon="vs-icon-check" circle plain type="primary">test</vs-button>
Copy the code
Use of keep-alive reference Vue forward refresh backward no refresh, simple page stack implementation [1]
Git address: https://github.com/JohnYu588/vase-ui
Reference 🍊
Girl wind vUE component library production complete walkthrough ~~
Build your own UI framework from scratch – publish to NPM
Vue forward refresh backward not refresh, simple page stack implementation
The resources
[1]
Vue forward refresh, refresh back do not stack to achieve simple page: https://juejin.cn/post/6844904002526642184.