从 ElementUI 源码的构建流程来看前端 UI 库设计

image

引言

因为业务须要,近期团队要搞一套本身的UI组件库,框架方面仍是Vue。而业界已经有比较成熟的一些UI库了,好比ElementUIAntDesignVant等。css

结合框架Vue,咱们选择在ElementUI基础上进行改造。但造轮子绝非易事,首先须要先去了解它整个但构建流程、目录设计等。html

本文经过分析ElementUI完整的构建流程,最后给出搭建一个完备的组件库须要作的一些工做,但愿对于想了解ElementUI源码或者也有搭建UI组件库需求的你,能够提供一些帮助!前端

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

目录结构解析

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

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

  • .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的完整流程是有帮助的。webpack

package.json

一般咱们去看一个大型项目都是从package.json文件开始看起的,这里面包含了项目的版本、入口、脚本、依赖等关键信息。git

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

main

项目的入口文件web

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

lib/element-ui.common.jscommonjs规范,而lib/index.jsumd规范,这个我在后面的打包模块会详细说明。shell

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中最重要的部分了,下面我会一一对其中的重要指令进行说明。
image

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,获得了官网的这种效果:
image

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,根据不一样的语言,分别生成不一样的文件:
image
这里面都是.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中:
image

最终官网展现出来的就是通过上面国际化处理后的页面:
image
支持切换不一样语言。

绕了一圈,回到主题: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 文件夹

image
这里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、动画的封装和公共方法。
image
咱们主要来看下入口文件,也就是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的组件示例。
image
其实从目录结构,咱们不难看出这是一个完整独立的Vue项目。主要用于官方文档的展现:
image
这里咱们主要关注下docs文件夹:
image
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> [中文]
// 一、将新建组件添加到components.json
// 二、添加到index.scss
// 三、添加到element-ui.d.ts
// 四、建立package
// 五、添加到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比较简单,备注也很清晰,它帮咱们作了下面几件事:

一、新建的组件添加到components.json

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

三、添加到 element-ui.d.ts,也就是对应的类型声明文件

四、建立package(咱们上面有提到组件相关的源码都在package目录下存放)

五、添加到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目录。

最后用一张图来描述上述整个打包流程:
image

发布流程

打包完成,紧跟着就是代码的发布了。Element中发布主要是用shell脚本实现的。

Element发布一共涉及三个部分:

一、git 发布

二、npm 发布

三、官网发布

发布对应的脚本是:

"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(项目贡献者及规范)

参考

❤️ 爱心三连击

1.若是以为这篇文章还不错,来个分享、点赞、在看三连吧,让更多的人也看到~

2.关注公众号前端森林,按期为你推送新鲜干货好文。

3.特殊阶段,带好口罩,作好我的防御。
image

相关文章
相关标签/搜索