구성 요소 라이브러리를 빌드하면

바퀴를 만드는 데 3일을 준다면

이 기사를 읽고 나면 다음과 같은 새로운 이해를 갖게 될 것입니다.

  1. 플러그인을 개별적으로 패키징하고 게시하는 방법

  2. 팀 또는 개인에 적합한 구성 요소 라이브러리 세트를 개발하는 방법

컴포넌트 라이브러리를 구축해야 하는 이유는 무엇입니까?

여기에서 나는 단순히 내 입장에서 예를 든다.

同事甲: Xiaoyi, 이 xxx 구성 요소를 포장했습니까?

同事乙: 네, 예전에 포장해 놓았으니 yyy 프로젝트에서 찾으실 수 있습니다.

B는 프로젝트 A의 원격 창고 주소를 제공하고 A는 전체 프로젝트를 가져온 다음 Xiao B가 패키징한 xxx 구성 요소를 찾아 사용했습니다. 그러나 곧 내 동료 A가 Xiao B에게 내가 원하는 효과가 귀하의 패키지와 약간 다르지만 귀하의 코드가 매우 낯설다고 말했습니다. 재포장 도와주실 수 있으신가요...

그래서 Xiao Yi는 침묵을 지켰습니다...

Xiaoyi로서 그는 회사에 유사한 프로젝트가 많은 이유를 생각해야 하지만 완전하고 독립적인 구성 요소 라이브러리가 없습니다. 그런 컴포넌트 라이브러리가 있으면 팀이 개발할 때 컴포넌트 라이브러리를 통해 필요한 컴포넌트를 찾을 수 없으며, 이는 팀 개발의 효율성을 위한 질적 도약입니다.

플러그인 및 구성 요소

제 생각에는 플러그인의 범위에는 플러그인의 하위 집합으로 이해할 수 있는 구성 요소가 포함됩니다.

일반적으로 플러그인은 전 ​​세계적으로 도입되며 주문형 도입 여부와 관계없이 구성 요소의 사용에는 글로벌 및 로컬이 모두 포함됩니다.

element-ui를 예로 들면 이것은 플러그인이자 우리가 말한 것 组件库입니다. 그러나 그 안에 있는 각각의 작은 모듈은 Checkbox 다중 선택 상자 구성 요소, 테이블 테이블 구성 요소 등과 같은 구성 요소입니다.

다음 세 가지 주요 측면에 불과한 특정 기능에 대해 더 많은 사용 및 개발 고려 사항이 있어야 합니다.

样式: 다양한 사용 시나리오에서 이 구성 요소의 상태, 크기, 색상 등을 나타냅니다.

功能: 현재의 비즈니스를 만족시키면서 발생할 수 있는 새로운 요구사항을 고려

规范: 코드는 깨끗하고 품질이 좋아야 하지만 성능도 필요합니다.

자신의 플러그인을 패키징하고 배포하는 방법

보다 간결하고 직관적인 소개를 위해 버튼 플러그인을 캡슐화하여 게시하겠습니다. (단순한 버튼, 이해하기 쉽도록)

먼저 단일 파일 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: '余大帅'
        }
    },
    computed:{
        computedStyle(){
            return { 
                height: this.btnHeight +'px', 
                lineHeight:this.btnHeight +'px', 
                width: this.btnWidth + 'px'
            }
        }
    },
    methods:{
        sayHi(name) {
            alert(`hi,${name}~`)
        }
    }
}
</script>

<style lang='scss' scoped>
    .yuiBtn{
        text-align: center;
        border: 1px solid #000000;
    }
</style>
复制代码

그럼 거기에 install메소드를 추가해야지 왜 install이냐고 묻지말고 vue-Router와 vuex 플러그인의 소스코드를 보면 인스톨메소드가 있음을 알 수 있다 그들을. 예를 들어 vue-Router에 대해 더 자세히 알아보십시오.

我们之所以能在vue项目中直接使用<router-view><router-link>,就是因为vue-Router中的install方法里已经帮我们全局注册这两个组件,而我们运行Vue.use(VueRouter)的时候便是执行的vue-Routerinstall 方法。

继续讲我们的插件install,以下是vue官网给出的插件install方法的模板,满足了多种需求。

MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或 property
  Vue.myGlobalMethod = function () {
    // 逻辑...
  }
  // 2. 添加全局资源
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVnode) {
      // 逻辑...
    }
    ...
  })
  // 3. 注入组件选项
  Vue.mixin({
    created: function () {
      // 逻辑...
    }
    ...
  })
  // 4. 添加实例方法
  Vue.prototype.$myMethod = function (methodOptions) {
    // 逻辑...
  }
}
复制代码

但是上述install方法中的功能并不合适我们现在想要的具象的UI组件。

因此需要以下写法,通过Vue.component()方法全局注册即可:

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

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

export default myPlugin

复制代码

没错开发插件到这就完事了,但是为了发布插件,你还得初始化一个npm包,并将我们刚刚写的插件放入其中。基本步骤如下:

  1. 初始化包
npm init 
复制代码
  1. 修改package.json中的入口文件信息:

"main": "index.js",

  1. 执行发包脚本
npm publish
复制代码

如果你没有npm官网账号,还得事先注册奥;未登录 npm 账号的情况下,会要求你进行登录。

展示下,这个简单的插件的目录结构:

发布成功后呢,那我就得恭喜你成为了一名插件开发者了。

关于使用的话,很简单咯:

先安装,我以目前的简易按钮插件为例(你现在就可以在项目中测试这个按钮的功能):

npm install yui-btn
复制代码

再引入:

// main.js
import yuibtn from 'yui-btn'
Vue.use(yuibtn)
复制代码

最后使用

// xx.vue
<YuiBtn />
复制代码

如果还是有疑问的,可以看下源码,github地址,点击这里 查看源码

补充一下发布插件的一些看法,有一些文章中介绍通过vue-cli初始化一个项目,然后开发插件,再发布。但是这会有个问题,你发布的插件的package.josn中的依赖信息将会是当前这个项目的依赖信息,显然这是不妥的。因此我的操作就是新建一个npm包,再移植插件代码,最后发布。

但是从另一个角度看的话,也是可以接受的--那就是开发组件库。如果当前项目就是针对于要开发的组件库而言的,那么依赖信息便不会显得过于累赘,同时仅限于vue的项目。 并且组件库涉及到分块打包等的问题,需要搭配webpack,而正好vue-cli内置了webapck。

如何封装并发布组件库

其实看完插件的开发与发布,你就应该明白了组件库的开发会是一个什么样的流程了。我前面也说过,组件库就是插件。

但是组件库是由众多组件集合而成的仓库,我们需要考虑到版本更新以及组件库在实际项目开发中的按需引入等问题:

所以大致可以从以下这几个方面考虑并开发组件库:

  1. UI设计

  2. 主题色控制

  3. 代码规范

  4. 版本管理

  5. 按需加载

  6. 优化打包

  7. 单元测试

  8. 文档说明

最合适想尝试搭建组件库的新手的方法如下:我们可以从最简单的方式开始搭建个人组件库,那就是不管37 21只看考虑组件全部引入的情况。以vue/cli 5.0.4为脚手架搭建项目,就按之前开发基础插件那样的话,我们很快就可以发布一个最简易版本的组件库demo:

新创建一个文件夹packages用来存放我们后期需要增加的组件,并为每个组件创建单独的文件夹。目录结构如下:

和之前写的单个插件类似,唯一不同的就是需要遍历执行vue.component().

我们的index.js如下:

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
};
复制代码

然后在package.json中设置 "main":"./packages/index.js", 就可以发布->安装->使用了。

当然前面只是最简单的版本,接下来开始完善之前提出的要求。

首先是代码规范的问题,我们一开始通过vue-cli创建的时候就可以选择eslint校验风格,所以无需多虑。

按需加载是非常关键的一步,其实就是对引入资源的优化,避免打包时将组件库中没用到的组件也打包了。大多个人组件库都是参照element-UI给出的方案: 给之前写好的组件各自增设install方法,打包的时候以多入口的形式,将组件各自打包。发布之后,需要在项目中按需引入组件库中的组件,并安装配置babel-plugin-import插件。。 这一步,我参考了掘金-悲伤日记写的一篇文章 深入 vue 组件库的按需引入。相关代码会在下面总结中展示。

组件库搭建上其他方面的完善个人感觉比较容易上手,查阅相关的资料和工具库文档不难实现。但由于时间有限,我准备面试的时间不够了!!!非常遗憾,暂时没法继续探索下去了,下次的更新脚手架的时候,应该就是更完整版本的了。

总结

下面四个问题是我在简易版的组件库模板开发过程中觉得有些疑问的地方,搞懂这几个问题能帮助我们更好得搭建组件库:

1.组件库的目录结构?

我给出的是最新版的vue-cli搭建出来并调整的目录结构,具体还得看你用的是哪个版本。

组件库根目录格式如下:

packages文件夹目录:

2.如何配置打包(生产)环境和组件库开发环境?

根据process.env.NODE_ENV当前所处的环境,我们可以增设两个配置文件,由环境决定使用哪个配置文件:

config.dev.js

我们需要修改根目录中的src文件夹名,以防止后续开发组件库中出现同名的src,而导致发布代码时文件被忽略。照理说打包之后应该也没啥影响。。。这个说法有待考证.

module.exports = {
    pages: {
        index: {
            entry: 'examples/main.js',
            template: 'public/index.html',
            filename: 'index.html'
        }
    },
}    
复制代码

config.build.js

这块的难点就是在于打包组件时需要根据不同的组件设置各自的打包入口。getComponentEntries()方法就是对入口的封装。

const fs = require('fs');
const path = require('path');
const join = path.join;
//  获取基于当前路径的目标文件
const resolve = dir => path.join(__dirname, '../', dir);

function getComponentEntries(path) {
    let files = fs.readdirSync(resolve(path));
    const componentEntries = files.reduce((fileObj, item) => {
        //  文件路径
        const itemPath = join(path, item);
        //  在文件夹中
        const isDir = fs.statSync(itemPath).isDirectory();
        const [name, suffix] = item.split('.');
        //  文件中的入口文件
        if (isDir) {
            fileObj[item] = resolve(join(itemPath, 'index.js'));
        }
        //  文件夹外的入口文件
        else if (suffix === 'js') {
            fileObj[name] = resolve(`${itemPath}`);
        }
        return fileObj;
    }, {});

    return componentEntries;
}

const buildConfig = {
    //  输出文件目录
    outputDir: resolve('lib'),
    productionSourceMap: false,
    //  webpack配置
    configureWebpack: {
        //  入口文件
        entry: getComponentEntries('packages'),
        //  输出配置
        output: {
            filename: '[name]/index.js',//  文件名称
            libraryTarget: 'umd',//  构建依赖类型
            libraryExport: 'default',//  库中被导出的项
            library: 'ywc-ui'//  引用时的依赖名
        }
    },
    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;

复制代码

3. 发布时,非打包的代码如何忽略提交?

我们当然希望自己的包越小越好,钱包除外~!

增设.npmignore文件,其实跟.gitignore的功能一样,可以理解成是对它的补充。

# 忽略目录
examples/
packages/
public/
dist/
common/
build/
config/

# 忽略指定文件
vue.config.js
jsconfig.json
复制代码

4.组件发布之后,如何在项目中引入并使用。

  1. 不考虑按需引入

那就跟引入element-UI一样:

先安装(下面按需亦是如此)

npm install ywc-ui
复制代码
// main.js
import yui from 'ywc-ui'
Vue.use(yui)
复制代码
// 目标文件中直接引入组件

<YuiButton />
复制代码
  1. 按需引入组件

首先安装我们的组件库,然后安装babel-plugin-component

npm install babel-plugin-component -D
复制代码

项目中增设 babel.config.js

module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    [
      'import',
      {
        libraryName: 'ywc-ui',
        style: (name) => {
          return `${name}/index.css`;
        },
        camel2DashComponentName: false, // 是否需要驼峰转短线
        camel2UnderlineComponentName: false // 是否需要驼峰转下划线
      }
    ]
  ]
}


复制代码
// main.js
import { YuiButton } from "ywc-ui";
Vue.use(YuiButton)

复制代码

文章虽然比较简短,但是一个组件库demo基本功能都已实现,大佬的话就别杠我了(手动狗头)!

->github点击这里 组件库模板地址

如果对这方面感兴趣的小伙伴,可以联系我,我计划过一段时间会开始系统性地开发自己的组件库,希望有小伙伴可以加入我的开源计划~缺人!!!

추천

출처juejin.im/post/7082770613223292935