Give me three days to build the wheel

After reading this article, you will learn the following things:

  1. How do I package and distribute plug-ins separately

  2. How to develop a team or individual component library

Why build a component library?

Here is a simple example from my side:

Colleague A: Xiao B, have you ever encapsulated this XXX component?

Colleague B: Yes, I encapsulated it before. You can find it in yyY project.

B gave a the remote warehouse address of the project, a took the whole project, and then found the XXX component encapsulated by b and used it. However, soon, colleague A said to small B, I want the effect of your encapsulation is slightly different, but I am very strange to your code. You can help me to encapsulate again below….

Then, small b fell into silence…

As b, he must be wondering why the company does not have a complete and independent component library with so many similar projects. If there is such a component library, then the team can find the required components through the component library when developing, which is not a qualitative take-off for the efficiency of team development.

Plug-ins and components

In my opinion, the scope of a plug-in includes components, which can be understood as a subset of plug-ins.

Generally, plug-ins are introduced globally, and there is a say whether they are introduced on demand. The use of components is both global and local.

Take the example of Element-UI, which is both a plugin and a component library, but each of its small modules is a component, such as the Checkbox component, the Table component, and so on.

They must have more use and development considerations for specific functions, in three broad ways:

Style: Refers to the state, size, color, and so on of the component in different usage scenarios

Function: Meet current business while considering possible new requirements

Specification: Code should be clean, quality, and performance

How do I package and distribute my plug-ins

For a more concise and intuitive introduction, I will use a button plug-in package and publish it. (Just a button, just to make it easier to understand)

First you need to create a single file, btn.vue,

<template> <div class='yuiBtn' :style="computedStyle" @click="sayHi(hi)"> {{btnName}} </div> </template> <script> export  default { name:'yuiBtn', data () { return { } }, props:{ btnName:{ type: String, default: 'YuiBtn' }, btnWidth:{ type: Number, default: 60 }, btnHeight:{ type: Number, default: 20, }, hi:{ type: String, default: 'Yu Dashuai'}}, computed: {computedStyle () {return {height: enclosing btnHeight + 'p', lineHeight: enclosing btnHeight + 'p', width: this.btnWidth + 'px' } } }, methods:{ sayHi(name) { alert(`hi,${name}~`) } } } </script> <style lang='scss' scoped> .yuiBtn{ text-align: center; border: 1px solid #000000; } </style>Copy the code

Then you need to add an install method to it. Don’t ask why it is install and not something else. If you look at the source code of vue-Router and Vuex plug-ins, you will find that they have install methods. Take a closer look at vue-router:

We were able to use


directly in the Vue project because the install method in vue-router already registered both components globally. Use (VueRouter) is the vue-router install method.

Continuing with our plug-in install, the following is a template for the plug-in install method on vue’s official website, which meets a variety of requirements.

MyPlugin.install = function (Vue, options) {
  // 1. Add a global method or property
  Vue.myGlobalMethod = function () {
    / / logic...
  }
  // 2. Add global resources
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVnode) {
      / / logic...}... })// 3. Inject component options
  Vue.mixin({
    created: function () {
      / / logic...}... })// 4. Add instance methods
  Vue.prototype.$myMethod = function (methodOptions) {
    / / logic...}}Copy the code

But the functionality in the install method above is not appropriate for the representational UI components we want now.

Vue.component() : Vue.component()

// index.js
import YuiBtn from './btn.vue'

const myPlugin = {    
    install(Vue) {
        Vue.component('YuiBtn', YuiBtn) 
    }
}

export default myPlugin

Copy the code

It’s true that developing the plug-in is done here, but in order to publish the plug-in, you need to initialize an NPM package and put the plug-in we just wrote into it. The basic steps are as follows:

  1. Initialize the package
npm init 
Copy the code
  1. Modify entry file information in package.json:

"main": "index.js",

  1. Execute the package sending script
npm publish
Copy the code

If you don’t have an NPM account, you have to register in advance. If you are not logged in to your NPM account, you will be asked to log in.

To show you the directory structure of this simple plug-in:

After that, I congratulate you on becoming a plugin developer.

It’s easy to use:

Install first, and I’ll use the current simple button plugin as an example (you can test this button in your project right now) :

npm install yui-btn
Copy the code

Introduction:

// main.js
import yuibtn from 'yui-btn'
Vue.use(yuibtn)
Copy the code

Finally using

// xx.vue
<YuiBtn />
Copy the code

If still in doubt, you can take a look at the source code, github address, click here to view the source code

To add some perspective on publishing plug-ins, there are articles about initializing a project through VUe-CLI, developing the plug-in, and then publishing it. There is a problem, however, that the dependencies in the package.josn of the plug-in you publish will be the dependencies of the current project, which is clearly not appropriate. So what I did was create a new NPM package, port the plug-in code, and release it.

But it is also acceptable to look at it from another Angle – that is, developing component libraries. If the current project is specific to the component library to be developed, then the dependency information is not overly burdensome and is limited to the VUE project. In addition, the component library involves the problems of block packaging and so on, which needs to be matched with Webpack, while vuE-CLI has webAPCK built in.

How do you package and publish component libraries

In fact, after seeing the development and release of plug-ins, you should understand the development of a component library will be what kind of process. As I said earlier, a component library is a plug-in.

However, a component library is a repository composed of many components, and we need to consider issues such as version updates and the introduction of component libraries on demand in actual project development:

So you can roughly consider and develop component libraries from the following aspects:

  1. UI design

  2. Theme color control

  3. Code specification

  4. Version management

  5. According to the need to load

  6. Optimization of packaging

  7. Unit testing

  8. documentation

The best way for beginners to try building a component library is as follows: We can start building a personal component library in the simplest way, which is to consider all the components introduced regardless of 37, 21. Using vue/ CLI 5.0.4 as a scaffolding project, we were able to release the simplest version of our component library demo as we had previously developed the base plugin:

Create a new folder called Packages to store the components we need to add later and create a separate folder for each component. The directory structure is as follows:

Similar to the individual plug-in I wrote earlier, the only difference is that vue.component() is executed iteratively.

Our index.js is as follows:

import Button from './yui-button/btn.vue';
import Input from './yui-input/inp.vue';

const components = [
  Button,
  Input
];
const install = function(Vue) {
  components.forEach(component => {
    Vue.component(component.name, component);
  });
}
export default {
  install
};
Copy the code

Then set “main”:”./packages/index.js” in package.json to publish -> install -> use.

Of course, the previous version is the simplest version, and now we can start to refine the requirements that were put forward before.

The first is the code specification, we can choose the ESLint verification style from the beginning of vue-CLI creation, so don’t worry about it.

Loading on demand is a key step that optimizes imported resources to avoid packaging components that are not used in the component library. Most personal component libraries follow the example given by Element-UI: add install methods to previously written components and package them individually in a multi-entry format. After r publishing, you need to import components from the component library as needed in your project and install and configure the babel-plugin-import plug-in. For this step, I refer to an article written by The Nuggets – Sad Diary that delves into the on-demand introduction of the VUE component library. The code is shown in the summary below.

Component library construction on other aspects of the improvement of personal feel relatively easy to use, refer to the relevant information and tool library documents is not difficult to achieve. But due to the limited time, I didn’t have enough time to prepare for the interview!! It’s a pity that we can’t continue exploring for the time being. When the scaffolding is updated next time, it should be a more complete version.

conclusion

The following four questions are some of the questions I found puzzling during the development process of the simple component library template. Understanding these questions can help us build the component library better:

1. The directory structure of the component library?

Depending on which version you are using, this is the directory structure that vue-CLI has built and adjusted.

The component library root directory format is as follows:

Packages folder directory:

2. How to configure packaging (production) environment and component library development environment?

Depending on the environment in which process.env.node_env is currently located, we can add two additional configuration files, and the environment determines which one to use:

config.dev.js

We need to change the SRC folder name in the root directory to prevent the same name from appearing in the component library later in the development and causing the file to be ignored when the code is published. It shouldn’t matter if you pack it… This statement is subject to verification.

module.exports = {
    pages: {
        index: {
            entry: 'examples/main.js'.template: 'public/index.html'.filename: 'index.html'}}},Copy the code

config.build.js

The difficulty is that you need to set up a package entry for each component. The getComponentEntries() method is a wrapper around the entry.

const fs = require('fs');
const path = require('path');
const join = path.join;
// Get the target file based on the current path
const resolve = dir= > path.join(__dirname, '.. / ', dir);

function getComponentEntries(path) {
    let files = fs.readdirSync(resolve(path));
    const componentEntries = files.reduce((fileObj, item) = > {
        // File path
        const itemPath = join(path, item);
        // In the folder
        const isDir = fs.statSync(itemPath).isDirectory();
        const [name, suffix] = item.split('. ');
        // The entry file in the file
        if (isDir) {
            fileObj[item] = resolve(join(itemPath, 'index.js'));
        }
        // The entry file outside the folder
        else if (suffix === 'js') {
            fileObj[name] = resolve(`${itemPath}`);
        }
        return fileObj;
    }, {});

    return componentEntries;
}

const buildConfig = {
    // Output file directory
    outputDir: resolve('lib'),
    productionSourceMap: false./ / webpack configuration
    configureWebpack: {
        // Import file
        entry: getComponentEntries('packages'),
        // Output configuration
        output: {
            filename: '[name]/index.js'.// File name
            libraryTarget: 'umd'.// Build the dependency type
            libraryExport: 'default'.// The exported item in the library
            library: 'ywc-ui'// The dependency name for the reference}},css: {
        sourceMap: false.extract: {
            filename: '[name]/index.css'}},chainWebpack: config= > {
        config.optimization.delete('splitChunks');
        config.plugins.delete('copy');
        config.plugins.delete('preload');
        config.plugins.delete('prefetch');
        config.plugins.delete('html');
        config.plugins.delete('hmr');
        config.entryPoints.delete('app'); }};module.exports = buildConfig;

Copy the code

3. How does unpackaged code ignore commit when published?

Of course we want our bags to be as small as possible, except for our wallets.

The addition of.npmignore file, like the.gitignore function, can be understood as a complement to it.

# ignore examples/ packages/ public/ dist/ common/ build/ config/Copy the code

4. How to introduce and use components in the project after they are released.

  1. Don’t consider on-demand import

That’s like introducing element-UI:

Install first (also on demand below)

npm install ywc-ui
Copy the code
// main.js
import yui from 'ywc-ui'
Vue.use(yui)
Copy the code
<YuiButton />Copy the code
  1. Import components as needed

First install our component library, then install babel-plugin-Component

npm install babel-plugin-component -D
Copy the code

Add babel.config.js to the project

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'].plugins: [['import',
      {
        libraryName: 'ywc-ui'.style: (name) = > {
          return `${name}/index.css`;
        },
        camel2DashComponentName: false.// Whether the hump turns short
        camel2UnderlineComponentName: false // Whether the hump needs to be underlined}}]]Copy the code
// main.js
import { YuiButton } from "ywc-ui";
Vue.use(YuiButton)

Copy the code

Although the article is relatively brief, but a component library demo basic functions have been realized, big guy’s words don’t bar me (manual dog head)!

-> Github Click here to address the component library template

If you are interested in this aspect, please feel free to contact me. I plan to systematically develop my own component library after a period of time. I hope you can join me in my open source plan.