关于element-ui:从-ElementUI-源码的构建流程来看前端-UI-库设计

8次阅读

共计 14941 个字符,预计需要花费 38 分钟才能阅读完成。

引言

因为业务须要,近期团队要搞一套本人的 UI 组件库,框架方面还是 Vue。而业界曾经有比拟成熟的一些UI 库了,比方 ElementUIAntDesignVant 等。

联合框架 Vue,咱们抉择在ElementUI 根底上进行革新。但 造轮子 绝非易事,首先须要先去理解它整个但构建流程、目录设计等。

本文通过剖析 ElementUI 残缺的构建流程,最初给出搭建一个齐备的组件库须要做的一些工作,心愿对于想理解 ElementUI 源码或者也有搭建 UI 组件库需要的你,能够提供一些帮忙!

咱们先来看下 ElementUI 的源码的目录构造。

目录构造解析

  • github:寄存了 Element UI 奉献指南、issuePR 模板
  • build:寄存了打包相干的配置文件
  • examples:组件相干示例 demo
  • packages:组件源码
  • src:寄存入口文件和一些工具辅助函数
  • test:单元测试相干文件,这也是一个优良的开源我的项目必备的
  • types:类型申明文件

说完文件目录,剩下还有几个文件(常见的 .babelrc.eslintc 这里就不开展阐明了),在业务代码中是不常见的:

  • .travis.yml:继续集成 (CI) 的配置文件
  • CHANGELOG:更新日志,这里 Element UI 提供了四种不同语言的,也是很贴心了
  • components.json:表明了组件的文件门路,不便 webpack 打包时获取组件的文件门路。
  • FAQ.md:ElementUI 开发者对常见问题的解答。
  • LICENSE:开源许可证,Element UI应用的是 MIT 协定
  • Makefile:Makefile 是一个实用于 C/C++ 的工具,在领有 make 环境的目录下,如果存在一个 Makefile 文件。那么输出 make 命令将会执行 Makefile 文件中的某个指标命令。

深刻理解构建流程前,咱们先来看下 ElementUI 源码的几个比拟次要的文件目录,这对于前面钻研ElementUI 的残缺流程是有帮忙的。

package.json

通常咱们去看一个大型项目都是从 package.json 文件开始看起的,这外面蕴含了我的项目的版本、入口、脚本、依赖等要害信息。

我这里拿出了几个关键字段,一一的去剖析、解释他的含意。

main

我的项目的入口文件

import Element from 'element-ui' 时候引入的就是 main 中的文件

lib/element-ui.common.jscommonjs 标准,而 lib/index.jsumd标准,这个我在前面的打包模块会具体阐明。

files

指定 npm publish 发包时须要蕴含的文件 / 目录。

typings

TypeScript入口文件。

home

我的项目的线上地址

unpkg

当你把一个包公布到 npm 上时,它同时应该也能够在 unpkg 上获取到。也就是说,你的代码既可能在 NodeJs 环境也可能在 浏览器环境 执行。为此你须要用 umd 格局打包,lib/index.jsumd 标准,由 webpack.conf.js 生成。

style

申明款式入口文件,这里是lib/theme-chalk/index.css,前面也会具体阐明。

scripts

开发、测试、生产构建,打包、部署,测试用例等相干脚本。scripts算是 package.json 中最重要的局部了,上面我会一一对其中的重要指令进行阐明。

bootstrap

"bootstrap": "yarn || npm i"

装置依赖,官网举荐优先选用 yarn(吐槽一句:我刚开始没看明确,想着bootstrap 不是之前用过的那个 ui 库吗 ????,起初看了下,原来 bootstrap 翻译过去是 疏导程序 的意思,这样看看也就大略了解了 ????)

build:file

该指令次要用来自动化生成一些文件。

"build:file": "node build/bin/iconInit.js & node build/bin/build-entry.js & node build/bin/i18n.js & node build/bin/version.js"

这条指令较长,咱们拆开来看:

build/bin/iconInit.js

解析 icon.scss,把所有的icon 的名字放在 icon.json 外面 最初挂在 Vue 原型上的 $icon 上。

最初通过遍历icon.json,失去了官网的这种成果:

build/bin/build-entry.js

依据 components.json 文件,生成 src/index.js 文件,外围就是 json-templater/string 插件的应用。

咱们先来看下 src/index.js 文件,他对应的是我的项目的入口文件,最下面有这样一句:

/* Automatically generated by './build/bin/build-entry.js' */

也就是 src/index.js 文件是由 build/bin/build-entry.js 脚本主动构建的。咱们来看下源码:

// 依据 components.json 生成 src/index.js 文件

// 引入所有组件的依赖关系
var Components = require("../../components.json");
var fs = require("fs");
// https://www.npmjs.com/package/json-templater 能够让 string 与变量联合 输入一些内容
var render = require("json-templater/string");
// https://github.com/SamVerschueren/uppercamelcase  转化为驼峰 foo-bar >> FooBar
var uppercamelcase = require("uppercamelcase");
var path = require("path");
// os.EOL 属性是一个常量,返回以后操作系统的换行符(Windows 零碎是 \r\n,其余零碎是 \n)var endOfLine = require("os").EOL;

// 生成文件的名字和门路
var OUTPUT_PATH = path.join(__dirname, "../../src/index.js");
var IMPORT_TEMPLATE =
  "import {{name}} from'../packages/{{package}}/index.js';";
var INSTALL_COMPONENT_TEMPLATE = "{{name}}";
// var MAIN_TEMPLATE = `/* Automatically generated by './build/bin/build-entry.js' */

// ...

// 获取所有组件的名字,寄存在数组中
var ComponentNames = Object.keys(Components);

var includeComponentTemplate = [];
var installTemplate = [];
var listTemplate = [];

ComponentNames.forEach((name) => {var componentName = uppercamelcase(name);

  includeComponentTemplate.push(
    render(IMPORT_TEMPLATE, {
      name: componentName,
      package: name,
    })
  );

  if (
    [
      "Loading",
      "MessageBox",
      "Notification",
      "Message",
      "InfiniteScroll",
    ].indexOf(componentName) === -1
  ) {
    installTemplate.push(
      render(INSTALL_COMPONENT_TEMPLATE, {
        name: componentName,
        component: name,
      })
    );
  }

  if (componentName !== "Loading") listTemplate.push(`  ${componentName}`);
});

var template = render(MAIN_TEMPLATE, {include: includeComponentTemplate.join(endOfLine),
  install: installTemplate.join("," + endOfLine),
  version: process.env.VERSION || require("../../package.json").version,
  list: listTemplate.join("," + endOfLine),
});

// 后果输入到 src/index.js 中
fs.writeFileSync(OUTPUT_PATH, template);
console.log("[build entry] DONE:", OUTPUT_PATH);

其实就是下面说的,依据 components.json,生成src/index.js 文件。

build/bin/i18n.js

依据 examples/i18n/page.json 和模版,生成不同语言的 demo,也就是官网 demo 展现国际化的解决。

ElementUI官网的国际化根据的模版是 examples/pages/template,依据不同的语言,别离生成不同的文件:

这外面都是 .tpl 文件,每个文件对应一个模版,而且每个 tpl 文件又都是合乎 SFC 标准的 Vue 文件。

咱们轻易关上一个文件:

export default {data() {
    return {
      lang: this.$route.meta.lang,
      navsData: [
        {
          path: "/design",
          name: "<%= 1 >",
        },
        {
          path: "/nav",
          name: "<%= 2 >",
        },
      ],
    };
  },
};

外面都有数字标示了须要国际化解决的中央。

首页所有国际化相干的字段对应关系存储在 examples/i18n/page.json 中:

最终官网展现进去的就是通过下面国际化解决后的页面:

反对切换不同语言。

绕了一圈,回到主题:build/bin/i18n.js帮咱们做了什么呢?

咱们思考一个问题:首页的展现是如何做到依据不同语言,生成不同的 vue 文件呢?

这就是 build/bin/i18n.js 帮咱们做的事件。

来看下对应的源码:

"use strict";

var fs = require("fs");
var path = require("path");
var langConfig = require("../../examples/i18n/page.json");

langConfig.forEach((lang) => {
  try {fs.statSync(path.resolve(__dirname, `../../examples/pages/${lang.lang}`));
  } catch (e) {fs.mkdirSync(path.resolve(__dirname, `../../examples/pages/${lang.lang}`));
  }

  Object.keys(lang.pages).forEach((page) => {
    var templatePath = path.resolve(
      __dirname,
      `../../examples/pages/template/${page}.tpl`
    );
    var outputPath = path.resolve(
      __dirname,
      `../../examples/pages/${lang.lang}/${page}.vue`
    );
    var content = fs.readFileSync(templatePath, "utf8");
    var pairs = lang.pages[page];

    Object.keys(pairs).forEach((key) => {
      content = content.replace(new RegExp(`<%=\\s*${key}\\s*>`, "g"),
        pairs[key]
      );
    });

    fs.writeFileSync(outputPath, content);
  });
});

解决流程也很简略:遍历 examples/i18n/page.json,依据不同的数据结构把tpl 文件的标记位,通过正则匹配进去,并替换成本人事后设定好的字段。

这样官网首页的国际化就实现了。

build/bin/version.js

依据 package.json 中的version, 生成examples/versions.json,对应就是残缺的版本列表

build:theme

解决款式相干。

"build:theme": "node build/bin/gen-cssfile && gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk",

同样这一条也关联了多个操作,咱们拆开来看。

build/bin/gen-cssfile

这一步是依据 components.json,生成package/theme-chalk/index.scss 文件,把所有组件的款式都导入到index.scss

其实是做了一个自动化导入操作,前面每次新增组件,就不必手动去引入新增组件的款式了。

gulp build –gulpfile packages/theme-chalk/gulpfile.js

咱们都晓得 ElementUI 在应用时有两种引入形式:

  • 全局引入
import Vue from "vue";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import App from "./App.vue";

Vue.use(ElementUI);

new Vue({
  el: "#app",
  render: (h) => h(App),
});
  • 按需引入
import Vue from "vue";
import {Pagination, Dropdown} from "element-ui";

import App from "./App.vue";

Vue.use(Pagination);
Vue.use(Dropdown);

new Vue({
  el: "#app",
  render: (h) => h(App),
});

对应两种引入形式,Element在打包时对应的也有两种计划。

具体如下:将 packages/theme-chalk 下的所有 scss 文件编译为 css,当你须要全局引入时,就去引入index.scss 文件;当你按需引入时,引入对应的组件 scss 文件即可。

这其中有一点,咱们须要思考下:如何把 packages/theme-chalk 下的所有 scss 文件编译为css

在平时的开发中,咱们打包、压缩之类的工作往往都会交给 webpack 去解决,然而,针对下面这个问题,咱们如果采纳 gulp 基于工作流去解决会更加不便。

gulp相干的解决就在 packages/theme-chalk/gulpfile.js 中:

"use strict";

const {series, src, dest} = require("gulp");
const sass = require("gulp-sass"); // 编译 gulp 工具
const autoprefixer = require("gulp-autoprefixer"); // 增加厂商前缀
const cssmin = require("gulp-cssmin"); // 压缩 css

function compile() {return src("./src/*.scss") // src 下的所有 scss 文件
    .pipe(sass.sync()) // 把 scss 文件编译成 css
    .pipe(
      autoprefixer({
        // 基于指标浏览器版本,增加厂商前缀
        browsers: ["ie > 9", "last 2 versions"],
        cascade: false,
      })
    )
    .pipe(cssmin()) // 压缩 css
    .pipe(dest("./lib")); // 输入到 lib 下
}

function copyfont() {return src("./src/fonts/**") // 读取 src/fonts 下的所有文件
    .pipe(cssmin())
    .pipe(dest("./lib/fonts")); // 输入到 lib/fonts 下
}

exports.build = series(compile, copyfont);

通过解决,最终就会打包出对应的款式文件

cp-cli packages/theme-chalk/lib lib/theme-chalk

cp-cli 是一个跨平台的 copy 工具,和 CopyWebpackPlugin 相似

这里就是复制文件到 lib/theme-chalk 下。

下面提到过屡次components.json,上面就来理解下。

components.json

这个文件其实就是记录了组件的门路,在自动化生成文件以及入口时会用到:

{
  "pagination": "./packages/pagination/index.js",
  "dialog": "./packages/dialog/index.js",
  "autocomplete": "./packages/autocomplete/index.js",
  // ...
  "avatar": "./packages/avatar/index.js",
  "drawer": "./packages/drawer/index.js",
  "popconfirm": "./packages/popconfirm/index.js"
}

packages

寄存着组件库的源码和组件款式文件。

这里以 Alert 组件为例做下阐明:

Alert 文件夹


这里 main.vue 对应就是组件源码,而 index.js 就是入口文件:

import Alert from "./src/main";

/* istanbul ignore next */
Alert.install = function (Vue) {Vue.component(Alert.name, Alert);
};

export default Alert;

引入组件,而后为组件提供 install 办法,让 Vue 能够通过 Vue.use(Alert) 去应用。

对于 install 能够看官网文档

packages/theme-chalk

这外面寄存的就是所有组件相干的款式,下面也曾经做过阐明了,外面有 index.scss(用于全局引入时导出所有组件款式)和其余每个组件对应的scss 文件(用于按需引入时导出对应的组件款式)

src

说了半天,终于绕到了 src 文件夹。

下面的 packages 文件夹是离开去解决每个组件,而 src 的作用就是把所有的组件做一个对立解决,同时蕴含自定义指令、我的项目整体入口、组件国际化、组件 mixins、动画的封装和公共办法。

咱们次要来看下入口文件,也就是src/index.js

/* Automatically generated by './build/bin/build-entry.js' */
// 导入了 packages 下的所有组件
import Pagination from "../packages/pagination/index.js";
import Dialog from "../packages/dialog/index.js";
import Autocomplete from "../packages/autocomplete/index.js";
// ...

const components = [
  Pagination,
  Dialog,
  Autocomplete,
  // ...
];

// 提供了 install 办法,帮咱们挂载了一些组件与变量
const install = function (Vue, opts = {}) {locale.use(opts.locale);
  locale.i18n(opts.i18n);
  // 把所有的组件注册到 Vue 下面
  components.forEach((component) => {Vue.component(component.name, component);
  });

  Vue.use(InfiniteScroll);
  Vue.use(Loading.directive);

  Vue.prototype.$ELEMENT = {
    size: opts.size || "",
    zIndex: opts.zIndex || 2000,
  };

  Vue.prototype.$loading = Loading.service;
  Vue.prototype.$msgbox = MessageBox;
  Vue.prototype.$alert = MessageBox.alert;
  Vue.prototype.$confirm = MessageBox.confirm;
  Vue.prototype.$prompt = MessageBox.prompt;
  Vue.prototype.$notify = Notification;
  Vue.prototype.$message = Message;
};

/* istanbul ignore if */
if (typeof window !== "undefined" && window.Vue) {install(window.Vue);
}
// 导出版本号、install 办法(插件)、以及一些性能比方国际化性能
export default {
  version: "2.13.2",
  locale: locale.use,
  i18n: locale.i18n,
  install,
  Pagination,
  Dialog,
  Autocomplete,
  // ...
};

文件结尾的:

/* Automatically generated by './build/bin/build-entry.js' */

其实在下面的 scriptsbuild/bin/build-entry.js中咱们曾经提到过:src/index.js是由 build-entry 脚本主动生成的。

这个文件次要做下以下事件:

  • 导入了 packages 下的所有组件
  • 对外裸露了 install 办法,把所有的组件注册到 Vue 下面,并在 Vue 原型上挂载了一些全局变量和办法
  • 最终将 install 办法、变量、办法导出

examples

寄存了 ElementUI的组件示例。

其实从目录构造,咱们不难看出这是一个残缺独立的 Vue 我的项目。次要用于官网文档的展现:

这里咱们次要关注下 docs 文件夹:

Element官网反对 4 种语言,docs一共有 4 个文件夹,每个文件夹外面的内容根本是一样的。

咱们能够看到外面全部都是 md 文档,而每一个 md 文档,别离对应着官网组件的展现页面。

其实当初各大支流组件库文档都是用采纳 md 编写。

咱们下面大抵理解了源码的几个次要文件目录,然而都比拟扩散。上面咱们从构建指令到新建组件、打包流程、公布组件残缺的看一下构建流程。

构建流程梳理

构建指令(Makefile)

平时咱们都习惯将我的项目罕用的脚本放在 package.json 中的 scripts 中。但 ElementUI 还应用了 Makefile 文件(因为文件内容较多,这里就选取了几个做下阐明):

.PHONY: dist test
default: help

# build all theme
build-theme:
    npm run build:theme

install:
    npm install

install-cn:
    npm install --registry=http://registry.npm.taobao.org

dev:
    npm run dev

play:
    npm run dev:play

new:
    node build/bin/new.js $(filter-out $@,$(MAKECMDGOALS))

dist: install
    npm run dist

deploy:
    @npm run deploy

pub:
    npm run pub

test:
    npm run test:watch

// Tip:
// make new <component-name> [中文]
// 1、将新建组件增加到 components.json
// 2、增加到 index.scss
// 3、增加到 element-ui.d.ts
// 4、创立 package
// 5、增加到 nav.config.json

我是第一次见,所以就去 Google 下,网上对 Makefile 对定义大略是这样:

Makefile 是一个实用于 C/C++ 的工具,较早作为工程化工具呈现在 UNIX 零碎中,通过 make 命令来执行一系列的编译和连贯操作。在领有 make 环境的目录下,如果存在一个 Makefile 文件。那么输出 make 命令将会执行 Makefile 文件中的某个指标命令。

这里我以 make install 为例简要阐明下执行流程:

  • 执行 make 命令,在该目录下找到 Makefile 文件。
  • 找到 Makefile 文件中对应命令行参数的 install 指标。这里的指标就是 npm install

构建入口文件

咱们看下 scripts 中的 dev 指令:

"dev":
"npm run bootstrap &&
npm run build:file &&
cross-env NODE_ENV=development
webpack-dev-server --config build/webpack.demo.js &
node build/bin/template.js",

首先 npm run bootstrap 是用来装置依赖的。

npm run build:file在后面也有提到,次要用来自动化生成一些文件。次要是 node build/bin/build-entry.js,用于生成Element 的入口 js:先是读取根目录的components.json,这个json 文件维护着 Element 所有的组件门路映射关系,键为组件名,值为组件源码的入口文件;而后遍历键值,将所有组件进行 import,对外裸露install 办法,把所有 import 的组件通过 Vue.component(name, component) 形式注册为全局组件,并且把一些弹窗类的组件挂载到 Vue 的原型链上(这个在下面介绍 scripts 相干脚本时有具体阐明)。

在生成了入口文件的 src/index.js 之后就会运行webpack-dev-server

webpack-dev-server --config build/webpack.demo.js

这个后面也提过,用于跑 Element 官网的根底配置。

新建组件

下面咱们提到了,Element中还用了 makefile 为咱们编写了一些额定的脚本。

这里重点说一下 make new <component-name> [中文] 这个命令。

当运行这个命令的时候,其实运行的是 node build/bin/new.js

build/bin/new.js比较简单,备注也很清晰,它帮咱们做了上面几件事:

1、新建的组件增加到components.json

2、在 packages/theme-chalk/src 下新建对应到组件 scss 文件,并增加到 packages/theme-chalk/src/index.scss

3、增加到 element-ui.d.ts,也就是对应的类型申明文件

4、创立 package(咱们下面有提到组件相干的源码都在package 目录下寄存)

5、增加到 nav.config.json(也就是官网 组件 左侧的菜单)

打包流程剖析

ElementUI打包执行的脚本是:

"dist":
  "npm run clean &&
   npm run build:file &&
   npm run lint &&
   webpack --config build/webpack.conf.js && webpack --config build/webpack.common.js && webpack --config build/webpack.component.js &&
   npm run build:utils &&
   npm run build:umd &&
   npm run build:theme",

上面咱们一一来进行剖析:

npm run clean(清理文件)

"clean": "rimraf lib && rimraf packages/*/lib && rimraf test/**/coverage",

删除之前打包生成文件。

npm run build:file(生成入口文件)

依据 components.json 生成入口文件 src/index.js,以及i18n 相干文件。这个在下面曾经做过剖析,这里就不再开展进行阐明。

npm run lint(代码查看)

"lint": "eslint src/**/* test/**/* packages/**/* build/**/* --quiet",

我的项目 eslint 检测,这也是当初我的项目必备的。

文件打包相干

webpack --config build/webpack.conf.js &&
webpack --config build/webpack.common.js &&
webpack --config build/webpack.component.js
build/webpack.conf.js

生成 umd 格局的 js 文件(index.js)

build/webpack.common.js

生成 commonjs 格局的 js 文件(element-ui.common.js),require时默认加载的是这个文件。

build/webpack.component.js

components.json 为入口,将每一个组件打包生成一个文件,用于按需加载。

npm run build:utils(转译工具办法)

"build:utils": "cross-env BABEL_ENV=utils babel src --out-dir lib --ignore src/index.js",

src 目录下的除了 index.js 入口文件外的其余文件通过 babel 转译,而后挪动到 lib 文件夹下。

npm run build:umd(语言包)

"build:umd": "node build/bin/build-locale.js",

生成 umd 模块的语言包。

npm run build:theme(生成款式文件)

"build:theme": "node build/bin/gen-cssfile && gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk",

依据 components.json,生成package/theme-chalk/index.scss。用gulp 构建工具,编译 scss、压缩、输入csslib目录。

最初用一张图来形容上述整个打包流程:

公布流程

打包实现,紧跟着就是代码的公布了。Element中公布次要是用 shell 脚本实现的。

Element公布一共波及三个局部:

1、git 公布

2、npm 公布

3、官网公布

公布对应的脚本是:

"pub":
  "npm run bootstrap &&
   sh build/git-release.sh &&
   sh build/release.sh &&
   node build/bin/gen-indices.js &&
   sh build/deploy-faas.sh",

sh build/git-release.sh(代码冲突检测)

运行 git-release.sh 进行 git 抵触的检测,这里次要是检测 dev 分支是否抵触,因为 Element 是在 dev 分支进行开发的。

#!/usr/bin/env sh
# 切换至 dev 分支
git checkout dev
# 检测本地和暂存区是否还有未提交的文件
if test -n "$(git status --porcelain)"; then
  echo 'Unclean working tree. Commit or stash changes first.' >&2;
  exit 128;
fi
# 检测本地分支是否有误
if ! git fetch --quiet 2>/dev/null; then
  echo 'There was a problem fetching your branch. Run `git fetch` to see more...' >&2;
  exit 128;
fi
# 检测本地分支是否落后近程分支
if test "0" != "$(git rev-list --count --left-only @'{u}'...HEAD)"; then
  echo 'Remote history differ. Please pull changes.' >&2;
  exit 128;
fi
# 通过以上查看,示意代码无抵触
echo 'No conflicts.' >&2;

公布 npm && 官网更新

dev分支代码检测没有抵触,接下来就会执行 release.sh 脚本,合并 dev 分支到master、更新版本号、推送代码到近程仓库并公布到npm(npm publish)。

官网更新大抵就是:将动态资源生成到 examples/element-ui 目录下,而后放到 gh-pages 分支,这样就能通过 github pages 的形式拜访。

到这里 ElementUI 的残缺构建流程就剖析完了。

ui 组件库搭建指北

通过对 ElementUI 源码文件和构建流程的剖析,上面咱们能够总结一下搭建一个齐备的 ui 组件库都须要做什么工作。

目录构造

目录构造对于大型项目是尤其重要的,正当清晰的构造对于前期的开发和扩大都是很有意义的。ui组件库的目录构造,我感觉 ElementUI 的就很不错:

|-- Element
    |-- .babelrc                           // babel 相干配置
    |-- .eslintignore
    |-- .eslintrc                          // eslint 相干配置
    |-- .gitattributes
    |-- .gitignore
    |-- .travis.yml                        // ci 配置
    |-- CHANGELOG.en-US.md
    |-- CHANGELOG.es.md
    |-- CHANGELOG.fr-FR.md
    |-- CHANGELOG.zh-CN.md                 // 版本改变阐明
    |-- FAQ.md                             // 常见问题 QA
    |-- LICENSE                            // 版权协定相干
    |-- Makefile                           // 脚本汇合(工程化编译)|-- README.md                          // 我的项目阐明文档
    |-- components.json                    // 组件配置文件
    |-- element_logo.svg
    |-- package.json
    |-- yarn.lock
    |-- .github                            // 贡献者、issue、PR 模版
    |   |-- CONTRIBUTING.en-US.md
    |   |-- CONTRIBUTING.es.md
    |   |-- CONTRIBUTING.fr-FR.md
    |   |-- CONTRIBUTING.zh-CN.md
    |   |-- ISSUE_TEMPLATE.md
    |   |-- PULL_REQUEST_TEMPLATE.md
    |   |-- stale.yml
    |-- build                              // 打包
    |-- examples                           // 示例代码
    |-- packages                           // 组件源码
    |-- src                                // 入口文件以及各种辅助文件
    |-- test                               // 单元测试文件
    |-- types                              // 类型申明

组件开发

参考大多数 UI 组件库的做法,能够将 examples 下的示例代码组织起来并裸露一个入口,应用 webpack 配置一个 dev-server,后续对组件的调试、运行都在此 dev-server 下进行。

单元测试

UI 组件作为高度形象的根底公共组件,编写单元测试是很有必要的。合格的单元测试也是一个成熟的开源我的项目必备的。

打包

对于打包后的文件,对立放在 lib 目录下,同时记得要在 .gitignore 中加上 lib 目录,防止将打包后果提交到代码库中。

同时针对引入形式的不同,要提供 全局引入 (UMD)和 按需加载 两种模式的包。

文档

组件库的文档个别都是对外可拜访的,因而须要部署到服务器上,同时也需具备本地预览的性能。

公布

组件库的某个版本实现开发工作后,须要将包公布到 npm 上。公布流程:

  • 执行测试用例
  • 打包构建
  • 更新版本号
  • npm 包公布
  • 打 tag
  • 自动化部署

保护

公布后须要日常保护之前老版本,个别须要留神一下几点:

  • issue(bug 修复)
  • pull request(代码 pr)
  • CHANGELOG.md(版本改变记录)
  • CONTRIBUTING.md(我的项目贡献者及标准)

参考

  • https://segmentfault.com/a/11…
  • https://zhuanlan.zhihu.com/p/…

❤️ 爱心三连击

1. 如果感觉这篇文章还不错,来个 分享、点赞、在看 三连吧,让更多的人也看到~

2. 关注公众号 前端森林,定期为你推送陈腐干货好文。

3. 非凡阶段,带好口罩,做好集体防护。

正文完
 0