You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
"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相关脚本时有详细说明)。
#!/usr/bin/env sh# 切换至dev分支
git checkout dev
# 检测本地和暂存区是否还有未提交的文件iftest -n "$(git status --porcelain)";thenecho'Unclean working tree. Commit or stash changes first.'>&2;exit 128;fi# 检测本地分支是否有误if! git fetch --quiet 2>/dev/null;thenecho'There was a problem fetching your branch. Run `git fetch` to see more...'>&2;exit 128;fi# 检测本地分支是否落后远程分支iftest"0"!= "$(git rev-list --count --left-only @'{u}'...HEAD)";thenecho'Remote history differ. Please pull changes.'>&2;exit 128;fi# 通过以上检查,表示代码无冲突echo'No conflicts.'>&2;
引言
由于业务需要,近期团队要搞一套自己的
UI
组件库,框架方面还是Vue
。而业界已经有比较成熟的一些UI
库了,比如ElementUI
、AntDesign
、Vant
等。结合框架
Vue
,我们选择在ElementUI
基础上进行改造。但造轮子
绝非易事,首先需要先去了解它整个但构建流程、目录设计等。本文通过分析
ElementUI
完整的构建流程,最后给出搭建一个完备的组件库需要做的一些工作,希望对于想了解ElementUI
源码或者也有搭建UI
组件库需求的你,可以提供一些帮助!我们先来看下
ElementUI
的源码的目录结构。目录结构解析
github:存放了
Element UI
贡献指南、issue
和PR
模板build:存放了打包相关的配置文件
说完文件目录,剩下还有几个文件(常见的
.babelrc
、.eslintc
这里就不展开说明了),在业务代码中是不常见的:Element UI
提供了四种不同语言的,也是很贴心了webpack
打包时获取组件的文件路径。ElementUI
开发者对常见问题的解答。Element UI
使用的是MIT
协议Makefile
是一个适用于C/C++
的工具,在拥有make
环境的目录下, 如果存在一个Makefile
文件。 那么输入make
命令将会执行Makefile
文件中的某个目标命令。深入了解构建流程前,我们先来看下
ElementUI
源码的几个比较主要的文件目录,这对于后面研究ElementUI
的完整流程是有帮助的。package.json
通常我们去看一个大型项目都是从
package.json
文件开始看起的,这里面包含了项目的版本、入口、脚本、依赖等关键信息。我这里拿出了几个关键字段,一一的去分析、解释他的含义。
main
项目的入口文件
lib/element-ui.common.js
是commonjs
规范,而lib/index.js
是umd
规范,这个我在后面的打包模块会详细说明。files
指定
npm publish
发包时需要包含的文件/目录。typings
TypeScript
入口文件。home
项目的线上地址
unpkg
当你把一个包发布到
npm
上时,它同时应该也可以在unpkg
上获取到。也就是说,你的代码既可能在NodeJs
环境也可能在浏览器环境
执行。为此你需要用umd
格式打包,lib/index.js
是umd
规范,由webpack.conf.js
生成。style
声明样式入口文件,这里是
lib/theme-chalk/index.css
,后面也会详细说明。scripts
开发、测试、生产构建,打包、部署,测试用例等相关脚本。
scripts
算是package.json
中最重要的部分了,下面我会一一对其中的重要指令进行说明。bootstrap
安装依赖, 官方推荐优先选用
yarn
(吐槽一句:我刚开始没看明白,想着bootstrap
不是之前用过的那个 ui 库吗 🤔,后来看了下,原来bootstrap
翻译过来是引导程序
的意思,这样看看也就大概理解了 🤣)build:file
该指令主要用来自动化生成一些文件。
这条指令较长,我们拆开来看:
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
文件。build/bin/i18n.js
根据
examples/i18n/page.json
和模版,生成不同语言的demo
,也就是官网 demo 展示国际化的处理。ElementUI
官网的国际化依据的模版是examples/pages/template
,根据不同的语言,分别生成不同的文件:这里面都是
.tpl
文件,每个文件对应一个模版,而且每个tpl
文件又都是符合SFC
规范的Vue
文件。我们随便打开一个文件:
里面都有数字标示了需要国际化处理的地方。
首页所有国际化相关的字段对应关系存储在
examples/i18n/page.json
中:最终官网展示出来的就是经过上面国际化处理后的页面:
支持切换不同语言。
绕了一圈,回到主题:
build/bin/i18n.js
帮我们做了什么呢?我们思考一个问题:首页的展示是如何做到根据不同语言,生成不同的
vue
文件呢?这就是
build/bin/i18n.js
帮我们做的事情。来看下对应的源码:
处理流程也很简单:遍历
examples/i18n/page.json
,根据不同的数据结构把tpl
文件的标志位,通过正则匹配出来,并替换成自己预先设定好的字段。这样官网首页的国际化就完成了。
build/bin/version.js
根据
package.json
中的version
,生成examples/versions.json
,对应就是完整的版本列表build:theme
处理样式相关。
同样这一条也关联了多个操作,我们拆开来看。
build/bin/gen-cssfile
这一步是根据
components.json
,生成package/theme-chalk/index.scss
文件,把所有组件的样式都导入到index.scss
。其实是做了一个自动化导入操作,后面每次新增组件,就不用手动去引入新增组件的样式了。
gulp build --gulpfile packages/theme-chalk/gulpfile.js
我们都知道
ElementUI
在使用时有两种引入方式:对应两种引入方式,
Element
在打包时对应的也有两种方案。具体如下:将
packages/theme-chalk
下的所有scss
文件编译为css
,当你需要全局引入时,就去引入index.scss
文件;当你按需引入时,引入对应的组件scss
文件即可。这其中有一点,我们需要思考下:如何把
packages/theme-chalk
下的所有scss
文件编译为css
?在平时的开发中,我们打包、压缩之类的工作往往都会交给
webpack
去处理,但是,针对上面这个问题,我们如果采用gulp
基于工作流去处理会更加方便。gulp
相关的处理就在packages/theme-chalk/gulpfile.js
中:经过处理,最终就会打包出对应的样式文件
cp-cli packages/theme-chalk/lib lib/theme-chalk
这里就是复制文件到
lib/theme-chalk
下。上面提到过多次
components.json
,下面就来了解下。components.json
这个文件其实就是记录了组件的路径,在自动化生成文件以及入口时会用到:
packages
存放着组件库的源码和组件样式文件。
这里以
Alert
组件为例做下说明:Alert 文件夹
这里
main.vue
对应就是组件源码,而index.js
就是入口文件:引入组件,然后为组件提供
install
方法,让Vue
可以通过Vue.use(Alert)
去使用。packages/theme-chalk
这里面存放的就是所有组件相关的样式,上面也已经做过说明了,里面有
index.scss
(用于全局引入时导出所有组件样式)和其他每个组件对应的scss
文件(用于按需引入时导出对应的组件样式)src
说了半天,终于绕到了
src
文件夹。上面的
packages
文件夹是分开去处理每个组件,而src
的作用就是把所有的组件做一个统一处理,同时包含自定义指令、项目整体入口、组件国际化、组件 mixins、动画的封装和公共方法。我们主要来看下入口文件,也就是
src/index.js
:文件开头的:
/* Automatically generated by './build/bin/build-entry.js' */
其实在上面的
scripts
的build/bin/build-entry.js
中我们已经提到过:src/index.js
是由build-entry
脚本自动生成的。这个文件主要做下以下事情:
packages
下的所有组件install
方法,把所有的组件注册到Vue
上面,并在Vue
原型上挂载了一些全局变量和方法install
方法、变量、方法导出examples
存放了
ElementUI
的组件示例。其实从目录结构,我们不难看出这是一个完整独立的
Vue
项目。主要用于官方文档的展示:这里我们主要关注下
docs
文件夹:Element
官网支持 4 种语言,docs
一共有 4 个文件夹,每个文件夹里面的内容基本是一样的。我们可以看到里面全部都是
md
文档,而每一个md
文档,分别对应着官网组件的展示页面。我们上面大致了解了源码的几个主要文件目录,但是都比较分散。下面我们从构建指令到新建组件、打包流程、发布组件完整的看一下构建流程。
构建流程梳理
构建指令(Makefile)
平时我们都习惯将项目常用的脚本放在
package.json
中的scripts
中。但ElementUI
还使用了Makefile
文件(由于文件内容较多,这里就选取了几个做下说明):我是第一次见,所以就去
Google
下,网上对Makefile
对定义大概是这样:这里我以
make install
为例简要说明下执行流程:make
命令, 在该目录下找到Makefile
文件。Makefile
文件中对应命令行参数的install
目标。这里的目标就是npm install
构建入口文件
我们看下
scripts
中的dev
指令:首先
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
。这个前面也提过,用于跑
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
打包执行的脚本是:下面我们一一来进行分析:
npm run clean(清理文件)
删除之前打包生成文件。
npm run build:file(生成入口文件)
根据
components.json
生成入口文件src/index.js
,以及i18n
相关文件。这个在上面已经做过分析,这里就不再展开进行说明。npm run lint(代码检查)
项目
eslint
检测,这也是现在项目必备的。文件打包相关
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(转译工具方法)
把
src
目录下的除了index.js
入口文件外的其他文件通过babel
转译,然后移动到lib
文件夹下。npm run build:umd(语言包)
生成
umd
模块的语言包。npm run build:theme(生成样式文件)
根据
components.json
,生成package/theme-chalk/index.scss
。用gulp
构建工具,编译scss
、压缩、输出css
到lib
目录。最后用一张图来描述上述整个打包流程:
发布流程
打包完成,紧跟着就是代码的发布了。
Element
中发布主要是用shell
脚本实现的。Element
发布一共涉及三个部分:1、git 发布
2、npm 发布
3、官网发布
发布对应的脚本是:
sh build/git-release.sh(代码冲突检测)
运行
git-release.sh
进行git
冲突的检测,这里主要是检测dev
分支是否冲突,因为Element
是在dev
分支进行开发的。发布 npm && 官网更新
dev
分支代码检测没有冲突,接下来就会执行release.sh
脚本,合并dev
分支到master
、更新版本号、推送代码到远程仓库并发布到npm
(npm publish)。官网更新大致就是:将静态资源生成到
examples/element-ui
目录下,然后放到gh-pages
分支,这样就能通过github pages
的方式访问。到这里
ElementUI
的完整构建流程就分析完了。ui 组件库搭建指北
通过对
ElementUI
源码文件和构建流程的分析,下面我们可以总结一下搭建一个完备的 ui 组件库都需要做什么工作。目录结构
目录结构对于大型项目是尤其重要的,合理清晰的结构对于后期的开发和扩展都是很有意义的。
ui
组件库的目录结构,我感觉ElementUI
的就很不错:组件开发
参考大多数
UI
组件库的做法,可以将examples
下的示例代码组织起来并暴露一个入口,使用webpack
配置一个dev-server
,后续对组件的调试、运行都在此dev-server
下进行。单元测试
UI
组件作为高度抽象的基础公共组件,编写单元测试是很有必要的。合格的单元测试也是一个成熟的开源项目必备的。打包
对于打包后的文件,统一放在
lib
目录下,同时记得要在.gitignore
中加上lib
目录,避免将打包结果提交到代码库中。同时针对引入方式的不同,要提供
全局引入
(UMD)和按需加载
两种形式的包。文档
组件库的文档一般都是对外可访问的,因此需要部署到服务器上,同时也需具备本地预览的功能。
发布
组件库的某个版本完成开发工作后,需要将包发布到 npm 上。发布流程:
维护
发布后需要日常维护之前老版本,一般需要注意一下几点:
参考
The text was updated successfully, but these errors were encountered: