06.ElementUI 2.X 源码学习:源码剖析之工程化(一)
0x.00 前言
在用了5章篇幅 ElementUI源码学习:从零开始搭建Vue组件库汇总 讲解了如何编写一个组件、发布npm以及生成展示文档之后。接下来将分析Element项目的代码结构,学习其工程化思想。
前端开发早已从瘦客户端(thin client)架构/中心服务器(server-centric)架构进入到胖客户端(fat client)架构,各家技术百花齐放,让人目不暇接,直呼学不动了!伴随项目开发的复杂度日益增高,开发中需要直面各种问题: 开发效率、产品质量、多人协作等。
前端工程化是什么?
前端工程化 就是为了应对上述问题,把软件工程相关的方法和思想应用到前端日常开发中,以 系统化的、规范化的、可度量的方法 用于前端项目的开发、运行和维护等阶段,从而提高开发效率、提高产品质量、减少不必要的重复工作时间、降低开发难度/风险、降低企业成本(降本增效)。
如今前端项目的开发、构建、部署等主要环节,涉及了项目构建、代码开发、分支管理、自动化测试、持续集成、项目部署、性能等内容。如何用工程化的思想让开发更加系统化、标准化?主要分为 模块化(组件化)、规范化、自动化 等多个方面。
1️⃣ 模块化
项目按照其功能/业务拆分成相互独立的模块,可以独立运行。每个模块只包含与其功能相关的内容,模块之间通过接口调用,降低模块间的耦合。 将一个大的系统模块化之后,每个模块都可以被高度复用。模块不等于功能,一个功能可能包含多个模块(功能 > 模块)。
模块化让项目便于依赖管理、利于性能优化、提高可维护性。 各技术实现方案如下:
- JS的模块化(CommonJS、 AMD、 CMD、UMD、ES6 Module)
- CSS的模块化(BEM 命名规范、CSS Module、CSS In JS)
- 资源模块化(webpack loaders)
2️⃣ 组件化
组件化是为了解决项目代码重复问题,将其拆分成多个独立的组件给不同的功能使用,提高系统的代码重用(复用)性和易维护性。
模块化vs组件化
组件化和模块化的中心思想都是 分而治之
, 将一个项目拆分成更小的颗粒度的单元(组件/模块
),降低业务开发的复杂度。
模块化、组件化它们术语是相似的,作为分治思想的体现,最终都实现了
高内聚,低耦合
。
通常认为“模块”比“组件”大。 项目模块化不一定要求组件化,在进行模块化拆分时可以完全不考虑代码重用。一般不会这么做,这不是 best practice。
组件化就如UI控件,可以在各个模块中使用。而模块化就比如一个消息列表界面,引用table组件实现。虽然它没有复用的需求,但我们也要把它封装成独立模块。
3️⃣ 规范化
规范是团队基本约定的内容,必须严格遵循,旨在增强团队开发协作、提高代码质量。
- 目录结构 (约定俗称)
- 编码规范[HTML、CSS、JS、图片、命名等规范] (eslint、prettier)
- 前后端接口规范 (Swagger RESTful)
- 组件文档规范
- Git分支管理 (Git Flow )
- Commit描述规范 (Commitizen)
- 设计规范 (Material Design、Ant Design)
4️⃣ 自动化
将工作流程内容标准化,通过工具实现全/半自动化完成重复的工作,减少人的操作,实现标准统一、高质量交付。
- 文件构建 (webpack)
- 持续集成/构建/部署 (Travis CI)
- 自动化测试 (Jasmine、Mocha+chai、Jest)
下面将通过解析element项目源码,从结构、功能、源码方面逐一解析,学习其模块化、组件化、规范化、自动化等多维度优秀实践。
0x.01 目录结构
0x.02 package.json
接下来将从package.json
文件看起,快速了解分析项目 。
package.json
是项目的清单, 定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证、git仓库等元数据)。
之前在 05.项目发布配置(github pages&npm package) 文章中提到了package.json
配置信息,下面将对element
项目的各项属性进行分析。
项目的 package.json
中有非常多的属性,可以大致分为以下几类:
- 必备属性(
name
、version
) - 描述信息(
description
、keywords
、homepage
、repository
、bugs
) - NPM脚本(
scripts
) - 依赖(
dependencies
、devDependencies
、peerDependencies
) - 协议(
license
) 指定软件的开源协议类型 - 目录文件相关(
main
、files
、typings
、faas
、unpkg
、style
)
必备属性
name
和 version
属性是必须的字段,这两个属性组成一个 npm 模块的唯一标识。
name
是一个包的唯一标识,包名不能重复,可以执行 npm view packageName
查看包名是否已被占用,并可以查看一些基本信息
依赖
根据此配置信息,运行 npm || yarn install
命令,自动下载所需的模块,也就是配置项目所需的运行和开发环境。
NPM脚本
指定了运行脚本命令的npm命令行缩写,覆盖整个项目的生命周期。下文将重点着墨讲解。
描述信息
记录项目的简介、关键字、项目主页、代码仓库、反馈issues等元信息。
协议
开源协议很多有很多,如何为自己的项目选合适的开源协议呢? 可以到 https://choosealicense.com/ 获取更详细的说明和指引。
不想劳神费力的可以使用速查图,参考自 如何选择开源许可证?
目录文件相关
main
main
属性指定程序的主入口文件,当在应用程序中导入此软件包时,应用程序会在该位置搜索模块的导出。在代码中引入整个 Element import ElementUI from 'element-ui';
,实际上引入的就是 lib/element-ui.common.js
中暴露出去的模块。
{
"main": "lib/element-ui.common.js",
}
files
files
属性用于描述 npm publish
后推送到 npm 服务器的文件列表,如果指定文件夹,则文件夹内的所有内容都会包含进来。也可以通过配置 .npmignore
文件来忽略文件上传。
{
"files": [
"lib",
"src",
"packages",
"types"
],
}
typings
typings
属性指定针对typescript的声明文件入口。
{
"main": "lib/element-ui.common.js",
"typings": "types/index.d.ts",
}
详细参考 TypeScript docs.
style
style
属性指定了样式入口文件。
{
"style": "lib/theme-chalk/index.css",
}
unpkg
unpkg
是一个前端常用的公共 CDN,它通过 URL 语法可以访问NPM上任何包的任何文件。
unpkg.com/:package@:version/:file
当把包发布到 npm 上时, 不仅可以 NodeJs 环境使用,也可以通过 unpkg 获取在浏览器环境执行,不过需要符合 umd
规范。
{
"unpkg": "lib/index.js",
}
main
属性值lib/element-ui.common.js
是 commonjs
规范,由build/webpack.common.js
打包生成。unpkg
属性值 lib/index.js
是 umd
规范,由build/webpack.conf.js
打包生成。关于打包模块功能会稍后详细说明。
设置 unpkg
属性后,访问 https://unpkg.com/element-ui,按照上述规则自动访问 https://unpkg.com/element-ui@2.15.1/lib/index.js。
在之前的me-vue-ui
包发布中,由于没有配置 unpkg
属性,访问 https://unpkg.com/me-vue-ui 时按照 main
属性定义的文件路径自动访问 https://unpkg.com/me-vue-ui@0.1.2/lib/me-vue-ui.common.js。
CDN引入
若浏览器环境引入组件,只需要通过 unpkg.com/element-ui 获取到资源,在页面上引入 js 和 css 文件即可开始使用。
CSS文件的路径是 style
属性值;js文件的路径是基于umd
规范的打包文件的路径--unpkg
属性值。
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
faas
用于faas deploy
配置。NPM脚本的pub
命令存在 sh build/deploy-faas.sh
调用,用于站点element.eleme.io
的发布部署,不过在2.15版本之后被移除了(具体使用情况无法重现)。详见commit feat: add change log 2.15.0 (#20692)
NPM脚本
scripts
属性指定了运行脚本命令的npm命令行缩写,各个脚本可以互相组合使用,这些脚本覆盖整个项目的生命周期(开发、测试、打包、部署)。
脚本使用注意事项
通配符
由于 npm 脚本就是 Shell 脚本,因为可以使用 Shell 通配符。
"lint": "jshint *.js"
"lint": "jshint **/*.js"
上面代码中,*
表示任意文件名,**
表示任意一层子目录。
执行顺序
如果 npm 脚本里面需要执行多个任务,需要明确它们的执行顺序。如果是 并行执行(即同时的平行执行),使用&
符号。
$ npm run script1.js & npm run script2.js
如果是 继发执行(即只有前一个任务成功,才执行下一个任务),使用 &&
符号。
$ npm run script1.js && npm run script2.js
element
项目定义了很多脚本,按照用途大致分为项目基础、文件构建、项目开发 、发布部署、项目测试等。
脚本命令调用 build 目录中的众多文件,自动完成大量重复性工作,从而减少人为错误、提高效率。下面将逐一分析讲解脚本命令的功能和作用。
关于
/build
目录下文件功能,本篇幅不做讲解,详见后续文章。
项目基础
npm run bootstrap
自动下载项目所需的模块,也就是配置项目所需的运行和开发环境。官方推荐使用 yarn
。
npm run clean
清除打包/测试生成的目录及文件,主要有lib
目录、test\unit\coverage
目录(跟测试代码覆盖率有关,详见后文)以及package\theme-chalk\lib
目录(跟主题有关,详见后文)。
需要安装
rimraf
包,用于递归删除目录所有文件。
npm run eslint 代码质量检查
基于 .eslintrc
和 .eslintignore
文件配置,调用 eslint
检测代码规范。--quiet
参数允报告错误,禁止报告警告。
项目使用自己封装的规则配置 eslint-config-elemefe
, 配置使用请参考前文 代码风格检查和格式化配置(ESlint & Prettier)。
{
"extends": "elemefe",
}
文件构建
npm run i18n
执行 build/bin/i18n.js
基于 examples/i18n/page.json
页面多语言配置和 examples/pages/template
目录下的所有模版文件,生成 zh-CN
、en-US
、es
、fr-FR
等四种语言的网站.vue
文件。
npm run build:file
该命令主要用于文件的自动化生成,其多个任务是 并行执行。
- 执行
build/bin/iconInit.js
生成examples/icon.json
图标集合文件。 - 执行
build/bin/build-entry.js
生成src/index.js
组件库入口文件。 - 执行
build/bin/i18n.js
生成官网的多语言网站文件。 - 执行
build/bin/version.js
生成examples/version.json
记录项目版本信息,用于网站版头部导航版本切换。
npm run build:theme
该命令主要用于项目的主题和样式生成。
- 执行
build/bin/gen-cssfile
生成packages/theme-chalk/index.scss
样式总入口文件。全量引入组件时,引用改样式如下import 'packages/theme-chalk/src/index.scss'
。 - 采用
gulp
进行样式构建,将packages/theme-chalk/src
下的scss
文件转换成css
文件,输出至packages/theme-chalk/src/lib
目录下;将packages/theme-chalk/src/fonts
下的字体文件压缩处理,输出至packages/theme-chalk/src/lib/fonts
目录下。 - 将构建内容
packages/theme-chalk/lib
拷贝到lib/theme-chalk
下。前面sytle
属性配置的路径文件lib/theme-chalk/index.css
就是这样生成的。
需要安装
cp-cli
包,用于文件和文件夹复制,无需担心跨平台问题。
npm run build:utils
该命令作用把 src
目录下除了 src/index.js
入口文件外的其他文件通过 babel
转译后,输出至 lib
文件夹下。
需要安装
cross-env
包,是一款运行跨平台设置和使用环境变量的脚本,不同平台使用唯一指令,无需担心跨平台问题。
npm run build:umd
该命令作用是执行 build/bin/build-locale.js
通过 babel
处理 src/locale/lang
目录下的文件,生成 umd
格式的文件,输出至 lib/umd/locale
目录下。
项目开发
npm run dev
该命令用于运行组件库的本地开发环境。
- 执行命令
npm run bootstrap
配置项目所需的运行和开发环境。 - 执行命令
npm run build:file
详解见前文,构建项目官网相关文件。 webpack-dev-server
提供一个本地服务(serve) 并运行项目网站(打包规则配置build/webpack.demo.js
);同时执行build/bin/template.js
文件启动监听examples/pages/template
目 录下模板文件,若内容发生变化,则重新生成网站文件。 webpack-dev-server具有 live reloading功能,网站内容会实时重新加载。
npm run dev:play
该命令用于组件库开发中的功能展示,运行效果如下图。
- 执行命令
npm run build:file
详解见前文,构建项目官网相关文件。 - 由于配置了如下环境变量
NODE_ENV=development PLAY_ENV=true
,可以在build/webpack.demo.js
打包文件中看到入口文件examples/play.js
,play.js
引用examples/play/index.vue
, 可以引入组件库任意组件用于功能展示。
发布部署
npm run deploy:build
该命令作用主要是打包构建项目官网内容,为网站部署做准备。
- 执行命令
npm run build:file
详解见前文,构建项目官网相关文件。 webpack --config build/webpack.demo.js
基于production
模式,打包生成内容输出至examples/element-ui/
目录下。echo element.eleme.io>>examples/element-ui/CNAME
往examples/element-ui/CNAME
文件中写入element.eleme.io
。Github Docs / Managing a custom domain for your GitHub Pages site
npm run deploy:extension
该命令作用主要是打包构建主题编辑器的 chorme 插件项目--Element Theme Roller
官方商城地址 。基于 production
模式打包生成内容输出至 examples/extension
目录下。
使用该插件可以自定义全局变量和组件的所有设计标记,并实时预览新主题并基于新主题生成完整的样式包,以供直接下载
npm run dist
该命令作用主要是构建组件库。
- 执行命令
npm run clean
,详见上文; - 执行命令
npm run build:file
,详见上文; - 执行命令
npm run lint
,详见上文; - 执行打包
webpack --config build/webpack.conf.js
,入口文件src/index.js
以umd
格式输出到lib/index.js
; - 执行打包
webpack --config build/webpack.common.js
,入口文件src/index.js
以commonjs2
格式输出到lib/element-ui.common.js
; - 执行打包
webpack --config build/webpack.component.js
,入口文件components.json
,将packages
目录下的组件,以commonjs2
格式分别输出到lib
目录,用于按需引入; - 执行命令
npm run build:utils
,详见上文; - 执行命令
npm run build:umd
,详见上文; - 执行命令
npm run build:theme
,详见上文。
npm run pub
该命令作用主要是组件库的发布、代码管理。
- 执行命令
npm run bootstrap
,详见上文; - 运行shell脚本
sh build/git-release.sh
,检查代码dev
分支是否存在冲突(No conflicts); - 运行shell脚本
sh build/release.sh
,合并dev分支到master分支、更新版本号、发布主题、push代码到远程仓库、发布组件库至NPM; - 执行文件
node build/bin/gen-indices.js
,提供algoliasearch
搜索功能,需要把examples/docs
目录下.md
文件内容格式化后上传algolia
,效果详见下图 。
♂️ 在
2.15.x
版本,pub
命令移除了最后一条任务指令sh build/deploy-faas.sh
,用于站点 https://element.eleme.io 的faas deploy
。
测试
实现项目自动化测试。
- karma测试执行过程管理工具(Test Runner)。
- Mocha 是运行在 Node.js 和浏览器上的功能丰富的 JavaScript 测试框架。
- Chai 是一个用于 Node.js 和浏览器的 BDD/TDD 断言库,可以与任何 JavaScript 测试框架便捷配对。
- Sinon.JS 用于对 JavaScript 隔离测试 spy, stub 和 mock。适用于任何单元测试框架。
测试脚本命名方式为 [组件名].spec.js
, 统一放在 test/unit/specs/
目录下。如果测试成功,karma-coverage
会在 test/unit/coverage
文件夹中生成测试覆盖率结果的网页。
npm run test
该命令用于启动项目测试,设置了参数 --single-run
执行一次测试之后,karma 会自动停掉。
npm run test:watch
该命令用于启动项目测试,执行结束后会继续监测文件是否变更,若发生变更,会重新执行一次测试。
受制于篇幅的问题,本文到此就结束了!后续文章将会继续分析学习工程化实践。
0x.03 链接汇总
点击以下链接,可以快速查看本系列其他文章:
0x.04 参考
https://zhuanlan.zhihu.com/p/359734011
http://www.ruanyifeng.com/blog/2016/10/npm_scripts.html
06.ElementUI 2.X 源码学习:源码剖析之工程化(一)的更多相关文章
- Dapper源码学习和源码修改
之前ORM比较火热,自己也搞了个WangSql,但是感觉比较low,大家都说Dapper性能好,所以现在学习学习Dapper,下面简单从宏观层面讲讲我学习的Dapper. 再了解一个东西前,先得学会使 ...
- Dapper源码学习和源码修改(下篇)
目录: Dapper源码学习和源码修改(上篇主要讲解入参解析) Dapper源码学习和源码修改(下篇主要讲解出参解析) 继上篇讲了下自己学习Dapper的心得之后,下篇也随之而来,上篇主要讲的入参解析 ...
- 07.ElementUI 2.X 源码学习:源码剖析之工程化(二)
0x.00 前言 项目工程化系列文章链接如下,推荐按照顺序阅读文章 . 1️⃣ 源码剖析之工程化(一):项目概览.package.json.npm script 2️⃣ 源码剖析之工程化(二):项目构 ...
- 08.ElementUI 2.X 源码学习:源码剖析之工程化(三)
0x.00 前言 项目工程化系列文章链接如下,推荐按照顺序阅读文章 . 1️⃣ 源码剖析之工程化(一):项目概览.package.json.npm script 2️⃣ 源码剖析之工程化(二):项目构 ...
- Mysql源码学习——源码目录结构
目录清单 目录名 注释 Bdb 伯克利DB表引擎 BUILD 构建工程的脚本 Client 客户端 Cmd-line-utils 命令行工具 Config 构建工程所需的一些文件 Dbug Fred ...
- 05.ElementUI源码学习:项目发布配置(github pages&npm package)
0x00.前言 书接上文.项目第一个组件已经封装好,说明文档也已编写好.下面需要将说明文档发布到外网上,以此来展示和推广项目,使用 Github Pages功能实现.同时将组件发布之 npm 上,方便 ...
- Java学习-039-源码 jar 包的二次开发扩展实例(源码修改)
最近在使用已有的一些 jar 包时,发现有些 jar 包中的一些方法无法满足自己的一些需求,例如返回固定的格式,字符串处理等等,因而需要对原有 jar 文件中对应的 class 文件进行二次开发扩展, ...
- nginx源码学习资源
http://www.cnblogs.com/yjf512/archive/2012/06/13/2548515.html nginx源码学习是一个痛苦又快乐的过程,下面列出了一些nginx的学习资源 ...
- nginx源码学习资源(不断更新)转
原文地址:http://www.cnblogs.com/yjf512/archive/2012/06/13/2548515.html nginx源码学习是一个痛苦又快乐的过程,下面列出了一些nginx ...
随机推荐
- 【原创】【基础】一文搞懂严蔚敏数据结构SqList &L和SqList L、ElemType &e和ElemType e
旁白 最近小渔夫在看严蔚敏.李冬梅<数据结构 c语言版>(第2版),学到第二章顺序表的实现时,看到函数参数一会是SqList &L.一会又是SqList L.一会ElemType ...
- aws EKS EFS 上安装mysql Operation notpermitted
在AWS EKS k8s.EFS nfs.mysql.changing ownership of '/var/lib/mysql/': Operation notpermitted 在aws eks ...
- 【VsCode】常用的快捷键
查找和替换: 查找:Ctrl +F 查找和替换:Ctrl +H编辑器和窗口管理相关快捷键: 文件之间切换:Ctrl+Tab 关闭当前窗口:Ctrl+W /Ctrl +F4 切出一个新的编辑器窗口(最多 ...
- Android Apk加固的初步实现思路(dex整体加固)
一.前 言 Android Apk加固的发展已经有一段时间了,相对来说本篇博客要记录的Android加壳的实现思路是4年的东西了,已经被老鸟玩烂了,Android加固的安全厂商也不会采用这么粗犷的方式 ...
- Linux中常见的150个命令(干货)
目录 线上查询及帮助命令 文件和目录操作命令 查看文件和内容处理命令 文件压缩及解压缩命令 信息显示命令 搜索文件命令 进程管理相关命令 用户管理命令 基础网络操作命令 深入网络操作命令 有关磁盘与文 ...
- Windows中的用户和组以及用户密码处理
目录 用户帐户 Windows 默认账户 Windows 内置用户账户 查看.创建和删除账户 组账户 内置组账户 组的查看.创建和删除 Windows中对用户密码的处理 LM-hash NTLM-ha ...
- nodejs-Stream(流)
Node.js Stream(流) 描述++++++++++++++++++++++++++++++++++++++++++++++++++++ Stream 是一个抽象接口,Node 中有很多对象实 ...
- Conda基本使用方法
anaconda/miniconda的安装 请点击查看我的博客 本教程全部命令操作均在CMD(win).terminal(win).终端(linux/Macos)中执行 使用前配置 因为anacond ...
- 【python】Leetcode每日一题-寻找旋转排序数组中的最小元素2
[python]Leetcode每日一题-寻找旋转排序数组中的最小元素2 [题目描述] 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组.例如,原数组nums ...
- JPEG头部解析
6.3 JPEG格式 6.3.1简介 微处理机中的存放顺序有正序(big endian)和逆序(little endian)之分.正序存放就是高字节存放在前低字节在后,而逆序存放就是低字 ...