06.ElementUI 2.X 源码学习:源码剖析之工程化(一)

前端工程化 就是为了应对上述问题,把软件工程相关的方法和思想应用到前端日常开发中,以 系统化的、规范化的、可度量的方法 用于前端项目的开发、运行和维护等阶段,从而提高开发效率、提高产品质量。 …

0x.00 前言

在用了5章篇幅 ElementUI源码学习:从零开始搭建Vue组件库汇总 讲解了如何编写一个组件、发布npm以及生成展示文档之后。接下来将分析Es 0 R s ? (lement项目的代码结构,学9 j ~ Z + q习其工程化思想。

前端开发早已从瘦客户端(thin client)架构/中心q A v服务器(server-centricu X ( s S)架构进入到胖客户端(fat client)] X a x } 5架构,各家技术百花齐放_ + 8,让人目不暇接,直呼学不动了!伴R 4 4 c k T S随项目开发的复杂| 8 } 2 H度日益增高,开发中需要直面各种问题: 开发效率、产品质量、多人协作等。

前端工程化是什么?

前端工程化 就是为了应对上述问题,把软件工程相关的方法和思想应用到前端日常开发中,以 系统化的、规范化的、可度量的方法 用于前端项目的开发、运行和维护等阶段,从而提高开发效率、提高产品质量、减少不必要的重复工作时间、降低开Q e V n发难度/风险、降低企l , % l . v p } F业成本(降本增效)。

如今前端项目的开发、构建、部署等主要环节,涉及了项目构建、代码开发、分支管理、自动化测试、持续集成、7 K # V d i m B K项目部署、性能等内容。如何用工程化的思想让开发更加系统化、标准化?主要分为 模块化(组件化)、规范化、自动化 等多个方面。

1️⃣ 模块化

项目按照其功能/业务拆分成相互独立的模块,可以独立运行。每个模块只包含与其功能相关的内容,模块之间通过接口调用,降低模块间的耦合。 将一个大的系统模块化之后,每个模块都可以被高度复用。模块不等于功能,一个功能可能包含多个模块(功能 > 模块)。

模块化让项目便于依赖管理、利于性能优化、提高可维护性。 各技术实现方案如下:

  • JS的模块化(CommonJS、 AMD、 CMD、UMD、Q H I $ UES6 Module)
  • CSS的模块化(BEM 命名规范、CSS Module、CSS In JS)
  • 资源模块化(webpac% 8 uk loaders)

2️⃣ 组件化

; M 3 N w件化是为了解决项目代码重复问题,将其拆分成多个独立的组件给不同的功能使用,提高系统的代码重用(复) + / x a 2 P用)性和易维护性。

模块T \ k 4 D O F c化vs组件化

组件化@ e 5 N t和模块化的中心思想都是 分而治之 , 将一个项目拆分成更小的颗粒度的单5 + * n 5 { { R e元(组件/模块),降低业务开发的复杂度。

模块化、组件化它们术语是相似的,作为分治思想的体现,最终都实现了 高内E k B W A +聚,低耦合
通常认为“模块”比“组件”大。 项目模块化不一定要求组件化,在进行模块化拆分时可以完全不考虑代码重用。一般不会这么做,这不是 best practice。
组件化就如UI控件,可以在各个模块中使用。而模块化就比如一个消息列表界面,引用table组件实现。虽然它没有复用的需求,但我们也要把它封装成独立模块。

3️⃣ 规范化

规范是团m r d N ` l ?队基本约定的内容,必须严格遵循1 n = v 3 1 –,旨在增强团队开发协作、提高代码质量。

  • 目录结构 (\ T {约定俗称)
  • 编码规范[HTML、CSS、JS、图片、命名等规范] (eslint、prettier)
  • 前后y i w = \ U 7 { }端接口规范 (Swagger RESTful)
  • 组件文档规范
  • Git分支管理 (Git Fl` C y t 9 ` 7 }ow )
  • Commit描述规范 (Commitizen)
  • 设计规范 (Material De1 x * ~ T G Usign、Ant Design)@ d % y g i y

4️⃣ 自动化

将工作流程内容标准化,通过工具实现全/半自动化完成重复的工作,减少人的操作,实现标准统一、高质量交付。

  • 文件构建 (webpack)
  • W * l 3 u J I W续集成/构建/部署 (Travis CI)
  • 自动化测试 (Jasmine、Mocha+chai、Jest)

下面将通过解析element项目源码,从结构、功能、源码方面逐一解析,学习其模块化、组件化、规范化、自动化等多维度优v & = S秀实践。

0x.01 目录结构

image.png

0x.02 package.json

接下来将从package.json文件看起,快速了解分析项目 。

package.json 是项目的清单, 定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证、git仓库等元数据)。

之前在 05.项目发布配置(github pages&npm package) 文章中提到了package.json配置信息,下面将对eX 8 L c zlement 项目的各项属性进行分析。

项目的 package.jH 5 # 8 x x xson 中有非常多的属性,可以大致分为以下几类:

  • 必备属性(nameversion)
  • 描述信息(descriptionkeZ ` ; N J T p _ywordshomepagerepositorybugs)
  • NPM脚本(sC Z k } 4cripts)
  • 依赖(dependenciesdevDependenciespeerDependencies)% a | $ V q e i x
  • 协议V X u g ((license) 指定软件的开源协议类型
  • 目录文件相关(mainfilestypingsfaasunpkgstyle)

必备属性

nameversion 属性是必须的字段,这两个属性组成一个 npm 模块的唯一标识。
name 是一个包的唯一标识,包名不* 9 #能重复,可以执行 npm view packageName 查看包名是否已被占用,并可以查看一些基本信息

image.png

依赖

根据此配置信息,运行 npm || yarn install 命令,自动下载所需的模块,也就是配置项目所需的运行和开发环境。

NPM脚本

指定( – ,了运行脚本命令的nT , S ` _ f ) r !pm命令行缩写,覆N G ] R盖整个项目的生命周期。下文将重点着墨讲解。

描述信息

记录项目的简介、关键字、项目主h K ] } ; T S ! L页、代码仓库、反馈isN Y \ ^suesf ) T G等元信息。

协议

开源协议很多有很多,如何为自己的项目选合适的开源协议m I C N呢? 可以到 https://choosealicense.com/ 获取更详细的说明和指引。

不想劳神费力的可以使用速查图,参考自 如何选择开源许可证?
image.png

目录文件相关

main

main 属性指定P r _ h ` B程序的主入口文件,当在应用程序中导入此软件包时,应用程序会在该位置搜索模块的导出。在代码中引入整个 Element import ElementUI from 'element-ui';,实际上引入的就是 lib/elemL K r ; 9 P y w Pent-ui.common.js 中暴露出去的模块。

{
"main": "lib/element-ui.common.js",
}

files

files 属性用e # V [ 9 G b { V于描述 npm publish后推送到 npm 服务器A c I % _ d ( L的文件列表,如果指定文件夹,则文件夹内的所有内容都会包含进来。也可以通过配置 .npmignoree u F o ? _ 文件来忽略文件上传。

{
"files": [
"lib",
"src",
"packages",
"types"
],
}

typinj k ? ,gs

tl _ k Rypings属性指定针对typescript的声明文件入口。

{
"main": "lib/element-ui.c2 / a U )ommon.js",
"typings": "types/ix r kndex.d.ts",
}

详细参考 TypeScript docs.

style

style属性指定了样式入口文件。

{
"style": "lib/theme-chalk/index.css",
}

unpkg

unpkg 是一个前端常用的公共 C9 3 w m 3DN,它通过 URL 语法可以访问NPM上任何包I E } U Q的任何文件。

unpkg.com/:pac9 C H U $ 8 \ wkage@:version/:file

当把包发布到 npm 上时, 不仅可以 NodeJs 环境使用,也可以通过 unpkg 获取在浏览器环境执行,不过需要符合 umd 规范。

{
"unpkg": "lib/index.js",
}

main 属性值lib/element-ui.Y D p A L d i q Pcommon.jscommonjs 规范,由build/webpack.commo} y P gn.js打包生成。unpkg属性值 lib/index.jsumd 规范,由build/webpack.m f u {conf.js打包生成。关于打包模块功能会稍后详细说明。

gaitubao_carbon (66) (1).png

设置 unpkg 属性后,访问 https://unpkg.coma : * Q/element-ui,按照上述规则自动访问 https://unpkgj U X 0 A / y ].com/element-ui@2.15.1/lib/index.js。

在之前的me-vue-ui包发布中,由于没} W ; K有配置 unpkg 属性,访问 https://` – & 5 aunpkg.com/me-vue-& 1 i A nui 时按照 main 属性定义的文件路径自动访问 https://unpkg.c[ 4 D & B t Gom/me-vue-ui@0.1.2/lib/me-vue-ui.common.jsh t Z i = % :

CDN引入

若浏览器环境引入组件,只8 ( 3 v @ kN A \ D d I 3 Q &要通过 unpkg.com/element-ui 获取到资源,在页面上引入 js 和 css 文件即可开始使用。
CSS文件* b K R @ ] K 7 h的路径是 s} u O k ] % R U (tyle 属性值;js文件的路径是基于umdv M 3 . q H c规范的打包文T d e M – A : X j件的路径–unpkg属性值。

<!-- 引入N t J L ? n 6样式 -t T H->
<link rel="stylesheet" href="https://unpkg.com/element-R W , + t xui/lib/theme-chalk@ X 1 b + \ b G w/index.css">
<!-- 引入组件库 -->
<script src="https://un| ` Epkg.com/element-ui/lib/index.js"><@ @ z a @ F;/script>

faas

用于faas deploy 配置。NPM脚本的pub命令存在 sh build/deploy-faas.sh调用,用于站点element.eleme.io的发布部署,不过在2.15版本之后被移除了(具体使用情况无法u ( N A [ L重现y i F X 3 h 7。详见commit feat: add change log 2.15.0 (#20692)

下载 (2).png

NPM脚本 ⭐

scripts属性指定了运行脚本命令的npm命令行缩写,各个脚本可以互相组q l h 3合使用,这些脚本覆盖整个项目的生命周期(开发、测试、打包、部署)。

脚本使用注意事项

通配符

由于 npm 脚本就是 Shell 脚本,因; = m 4为可以使用 Shell 通配符。

"lint": "jshint *.js"
"lint": "jshint **/*.js"

上面代码中,* 表示任意文件名,** 表示任意一层子目录。

执行顺序

如果 npm 脚本里面需要执行多个任务,需要明确它们的_ B G v U R V执行顺序。如果是 并行执行(即同时的平行执行),使用&符号。

$ npm run script1.js & npm run script2.js

如果是 继发执行(即只有前一个任务成功,才执行下一个任务\ G ^ P),使用 && 符号。

$ npm run script1.js && npm run script2.js

element 项目定义了很多脚本,按照用途大致分为项目基础、Q u &文件构建、项目开发 、发布部署、4 [ o J 5项目测试等。
脚本命令调用 build 目录中的众多文件,自动完成大量重复性工作,从而减少人为错误、提高效率。下面将逐一分析讲解脚本命令的功能和作用。

关于 /build 目录下文件功能,本篇幅不做讲解,详见后续文章。

项目基础

npm run bootstrap

image.png

自动下载项目所需的模块,也就是配置项目所需的运行和开发环境。官方推荐使用 yarn

npm run clean

image.png

清除O q _ # s N J 8打包/测试生成的目录及文件,主要有lib目录、test\unit\coverage 目录(跟测试代码覆盖率有关,详见后文)以及package\theme-chalk\lib目录(跟主题有3 \ / u ;关,详见后文)。

需要安装 rimraf 包,用于递归删除目录所有文件。

npm run eslint 代码质量检查

image.png

基于 .eslintrc.eslintignore 文件配置,调用 eslint 检测代码规范。--quiet参数允报告错误,禁止p \ q报告警告。

项目使用自己封z Y 7 ! X U h p *装的规则K k # ; T 8 ]配置 eslint-config-elemefe , 配置使用请参考前文 代码风格检查和格式化配置(ESlint &Y 9 – ^ S x Prettier)。

{
"extends": "elemefe",
}

文件构建

npm run i18n

image.png

执行 build/bin/i18n.js 基于 examples/i18n/pagea d C K N $ i.json页面多语言配置和 examples/pages/template 目录下的所有模版文件,生成 zh-CNen-USesfr-FR等四种语言的网站.P \ Y a + ( 6vue文件。

npm r` Z N _un build:file

image.png

该命令主要用于文件的自动化生成,其多个任务是 并行执行

  • 执行 build/bin/Y t l K u ; \ | IiconInit.js 生成 examples/icon.json) f 1 Q标集合文件。
  • 执行 build/bin/build-entry.jX G a ) 7 bs 生成 src/index.js 组件库入口文件。
  • 执行 build/bin/i18n.js 生成官网的多语言网站文件。
  • 执行 build/bin/version.js 生成 examples/verC 9 _ w U G * lsion.json 记录项目版本信息,用于网站版头部导航版本切换。

npm run build:theme

image.png

该命令主要用于项目的主题和样式生成。

  1. 执行 build/bin/gen-cssfile 生成 packages/theme-chall I &k/indexR 1 $ M i K s L Z.scss 样式总入口文件} \ ! [ . k。全量X \ A y引入组件时,引用改样式如下5 I ^ import 'packages/theme-chalk/src/index.scss'
  2. 采用 gulp 进行样式构建,将packages/theme-chalk/srE # Y d M M ( Wc下的 scss 文件转换成 css 文件,输出至packages/theM 9 ame-chalk/src/lib目录下;将packages/theme-chalk/src/fonts下的字体文件压缩处理,输出至 packages/theme-chalk/src/lib/fonts 目录下。
  3. 将构建内容 packages/theme-chalk/lib 拷贝到 lib/theme-chalk 下。前面 sytle 属性配置的路径文件 lib/theme-b ] `chalk/index.css 就是这样生成的。

需要安装 cp-cli 包,用于文件和文件夹复制,无需担心跨平台问题。

npmk L F W , \ J # run build:utils

image.png

该命令作用把 src 目录下除了 srD K ! 0 b ` 0 ]c/index.js 入口文件外的其他文件通过 bv I g ; 0abel 转译后,输出至 lib 文件夹下。

需要安装 c5 J +ross-env 包,是一款运$ ! X p行跨平台设置和使P $ y 3用环境变量的脚本,不同平台使用唯一指令,无需担心跨平台问题。

npm run build:umd

image.png

该命令作用是执行 build/bin/build-locale.js 通过 babel 处理 src/locale/lang 目录下的文件,生成 umd 格式的文件,输出至 lib/umd/locale 目录下。

项目开发

npm run dev

image.png

该命令用于运行组件库的本地开发环境。

  1. 执行命令npm run bootstrap 配置项目所需的运行和开发环境。
  2. 执行命令npm run build:file 详解见前文,构建项目官网相关文件。0 | s B
  3. webpack-dev-server 提供. 2 f 6 \ j / ? R一个本地服务(serve) 并b = C运行项目网站(打包规则配置 build/webpack.demo.js);同时执行build/bin/template.js文件启动监听examples/paO , T W *ges/template目 录下模板文件,若内容发生e d y J O I , z B变化,则重新生成网站文件。 webpack-dev-server0 ] # [ s # F具有 live reloading功能,网站内容会实时重新加载。

npm run dev:plas j j e P O ` / |y

image.png

该命令用于组件库开发中的功能展示,运行效果如下图。

  1. c m ; V s ,行命令npm run build:file 详解见前文,构建项目官网相关文件。
  2. 由于配置了如下环境变量NODE_ENV=\ y + d L K Adevelopmen} h & b l j M ct PLAY_ENV=m g p n etV L V B 5 Irue,可以在build/webpack.demo.js打包文件中看到入口文件examples/play.jk ) d Bs, play.js 引用 examples/play/index.vue, 可以引入组件库任意组件用于功能展示。

image.png

发布部署

npm run deploy:build

image.png

该命令作用主要是打包构建项目官网内容,为网站部署做准备。

  1. 执行命令npm run build:file 详解见前文,构建项目官网相关文件。
  2. web{ 1 spack --config build/webpack.demo.jt ^ a B B ; H D 1s) g Y M !prod+ ; H suc5 J g f A W [ ption 模式,打包生成内容输出至examples/element-ui/目录下。
  3. echo element.eleme.io>>examples/element-ui/CNAMEexamples/elementr I { S L-ui/CNAME文件中写入element.eleme.io 。Gc ? =ithub Docs / ManD n Aaging a cuV { g J ,st– [ 6 B Z vom domain for your GitHub Pages site

nD 1 3 rpm run deploy:extension

image.png

该命令作用主要是打包构建主题编辑器的 chorme 插件项目–Element Theme Roller 官方商城地址 。基于 production 模式打包生成内容输出至 examples/extension 目录下。

使用该插件可以自% , M @ G L定义全局变量和组件的v M A所有设计标记,并实时预览新主题并基于新主题生成完整的样式包,以供直接下载

image.png

image.png

npm run dist ⭐

image.png

该命令作用主要是构建组件库。

  1. 执行命令npm run clean,详见上文;
  2. 执行命令npm run build:fR 6 | T $ / g X file,详见上文;
  3. 执行命令npm run lint,详见上文;
  4. 执行打包webpack --config build/webpack.Q q R q } Cconf.js,入口文件 src/index.jsumd 格式输出到 lib/index.js;
  5. 执行打包webpack -n H v E U E-config build/webpack.commt y + |on.js,入口文件 src/index.jscommonjs2格式输出到l d H ^ lib/element-u8 1 a D 1 L T F |i.common.js;
  6. 执行打包webpack --config build/webpack.component.js,o H ! c / & – J m入口文件 components.json,将packages目录下的组件,以commonjs2格式分别输出到lib目录,用于按需引入;
  7. 执行命令npm run build:utils ,详见上文;
  8. 执行命令npm run build:umd ,详见上文;
  9. 执行命令npm run build:theme,详见上文m p 0 I r

npm run pub ⭐

image.png

该命令作用主要是组件库的发布、代码管理。

  1. 执行命令npm run bootstr] $ 3 2 % q u C rap,) C 9 y = 2 (详见上文;
  2. 运行shell脚本sh build/git-release.sp ) G T R J + % Sh ,检查代码 dev 分支是否存在冲突(No confliW t + i ?cts);
  3. 运行shell脚本sh build/release.sh,合并deq s @ } + & \ i ,v分支到master分支、更新版本号、发布主题、push代码到远程仓库、发布组件库至NPM;
  4. 执行文件node build/bin/gen-indices.js,提供 algoliasearch 搜索功能,需要把 examples/docs 目录下 .md 文件内( ) m y ^ r容格式化后上传 algolia,效果详见下图 。

image.png

‍♂️ 在 2.15.x 版本,pub 命令移除了最后一条任务指令sh build/deploy-faas.sh ,用于站点 h\ X mttps://element.eleme.io 的 faas deploy

测试

实现项目自动化测试。

  • karma测试执行过程管理工具(V R I R i F qTest RuG c l ; y A B _ znner)。
  • Mocha 是运行在 Node.js 和浏览器上的功能丰富的 JavaScript 测试框架。
  • Chai 是一个用o = $于 Node.js 和浏览器的 BDD/TDD 断言库,可以与任何 Java0 y g M jScript 测试框架便捷配对。
  • Sinon.JS 用于对 JavaScript 隔离测试 spy, stub 和 mock。适用于任何单元测试框架。

测试脚O 1 W C ; J G v本命名方式为 [组件名].sp. M V h W $ec.js , 统一放在 test/unit/specs/ 目录下。如果测试成功,karma-covr , perage 会在 test/unit/covera7 _ x mge 文件夹中生成测试覆盖率结果的网页。

npm run test

image.png

该命令用于启动项目测试,设置了参数 --single-run 执行一次测试之后,karma 会自动停掉。

image.png

npm run test:watch

image.png

该命令用于启动项目测试,执行结束后会~ 2 9 v e继续监测文件是否变更,若发生变更,会重新执行一次测试。
image.png


受制于篇幅的问题,本文到此就结束了!后续文章将会继续分析学习工程化实践。

0xE % 9 + T a L \.03 链接汇总

点击以下链接,可以快速查看本系列其他文章$ | W V [

ElementUI源码学习:从零开始搭建Vue组件s u Z R n I R O }库汇总

专栏/Element 2.XG M 2 F V V S \ 5 源码学习

0x.04 参考

https://zhuanlan.zhihu.com/p/359734011
http://www.ruanyifeng.com/blog/2016/10/npm_sc} ; 2 S ) z #ripts.html

上一篇 2021年6月4日 上午12:49
下一篇 2021年6月4日 上午12:49