前端工程化汇总
随着前段项目的日益复杂,前段有必要进行工程化。前段工程化主要包括4个方面:模块化、组件化、规范化和自动化。
一、模块化
背景:浏览器本身并不提供模块管理的机制,为了调用各个模块,有时不得不在网页中,加入一大堆script标签。这样就使得网页体积臃肿,难以维护,还产生大量的HTTP请求,拖慢显示速度,影响用户体验。
为了解决这个问题,前端的模块管理器(package management)应运而生。它可以轻松管理各种JavaScript脚本的依赖关系,自动加载各个模块,使得网页结构清晰合理。不夸张地说,将来所有的前端JavaScript项目,应该都会采用这种方式开发。
基础知识:
·主流模块化标准分为AMD(异步模块定义)和CMD (通用模块定义)。
·RequireJS 和 SeaJS 都是很不错的模块加载器,RequireJS遵循的是AMD规范,SeaJS遵循的是CMD规范。
·NPM的全称是Node Package Manager,是一个NodeJS包管理和分发工具,已经成为了非官方的发布Node模块(包)的标准。Nodejs自身提供了基本的模块,但是开发实际应用过程中仅仅依靠这些基本模块则还需要较多的工作。幸运的是,Nodejs库和框架为我们提供了帮助,让我们减少工作量。但是成百上千的库或者框架管理起来又很麻烦,有了NPM,可以很快的找到特定服务要使用的包,进行下载、安装以及管理已经安装的包。
·Webpack:是一个前端工具,可以让各个模块进行加载,预处理,再进行打包,它能有Grunt或Gulp所有基本功能,并有许多其他优点。
·Babel:是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。这意味着,你可以现在就用ES6编写程序,而不用担心现有环境是否支持。
1.JS的模块化
在ES6之前,JavaScript一直没有模块系统,这对开发大型复杂的前端工程造成了巨大的障碍。对此社区制定了一些模块加载方案,如CommonJS、AMD和CMD等,某些框架也会有自己模块系统,比如Angular1.x。
现在ES6已经在语言层面上规定了模块系统,完全可以取代现有的CommonJS和AMD规范,而且使用起来相当简洁,并且有静态加载的特性。
规范确定了,然后就是模块的打包和加载问题:
①用Webpack+Babel将所有模块打包成一个文件同步加载;
②用SystemJS+Babel分模块异步加载;
③将两者结合在一起。
2.CSS的模块化
虽然SASS、LESS、Stylus等预处理器实现了CSS的文件拆分,但没有解决CSS模块化的一个重要问题:选择器的全局污染问题。
按道理,一个模块化的文件应该要隐藏内部作用域,只暴露少量接口给使用者。而按照目前预处理器的方式,导入一个CSS模块后,已存在的样式有被覆盖的风险。虽然重写样式是CSS的一个优势,但这并不利于多人协作。
为了避免全局选择器的冲突,各厂都制定了自己的CSS命名风格:
·BEM风格;
·Bootstrap风格;
·Semantic UI风格;
·NEC风格;
毕竟是弱约束。选择器随着项目的增长变得越多越复杂,然后项目组里再来个新人带入自己的风格,就更加混乱了。
所以我很赞同这句话:与其费尽心思地告诉别人要遵守某种规则,以规避某种痛苦,倒不如从工具层面就消灭这种痛苦。
从工具层面,社区又创造出Shadow DOM、CSS in JS和CSS Modules三种解决方案。
·Shadow DOM是WebComponents的标准。它能解决全局污染问题,但目前很多浏览器不兼容,对我们来说还很久远;
·CSS in JS是彻底抛弃CSS,使用JS或JSON来写样式。这种方法很激进,不能利用现有的CSS技术,而且处理伪类等问题比较困难;
·CSS Modules仍然使用CSS,只是让JS来管理依赖。它能够最大化地结合CSS生态和JS模块化能力,目前来看是最好的解决方案。Vue的scoped style也属于这一种。
二.组件化
分治的确是非常重要的工程优化手段。在我看来,前端作为一种GUI软件,光有JS/CSS的模块化还不够,对于UI组件的分治也有着同样迫切的需求:
如上图,这是我所信仰的前端组件化开发理念,简单解读一下:
- 页面上的每个 独立的 可视/可交互区域视为一个组件;
- 每个组件对应一个工程目录,组件所需的各种资源都在这个目录下就近维护;
- 由于组件具有独立性,因此组件与组件之间可以 自由组合;
- 页面只不过是组件的容器,负责组合组件形成功能完整的界面;
- 当不需要某个组件,或者想要替换组件时,可以整个目录删除/替换。
其中第二项描述的就近维护原则,是我觉得最具工程价值的地方,它为前端开发提供了很好的分治策略,每个开发者都将清楚的知道,自己所开发维护的功能单元,其代码必然存在于对应的组件目录中,在那个目录下能找到有关这个功能单元的所有内部逻辑,样式也好,JS也好,页面结构也好,都在那里。
组件化开发具有较高的通用性,无论是前端渲染的单页面应用,还是后端模板渲染的多页面应用,组件化开发的概念都能适用。组件HTML部分根据业务选型的不同,可以是静态的HTML文件,可以是前端模板,也可以是后端模板:
不同的技术选型决定了不同的组件封装和调用策略。
基于这样的工程理念,我们很容易将系统以独立的组件为单元进行分工划分:
由于系统功能被分治到独立的模块或组件中,粒度比较精细,组织形式松散,开发者之间不会产生开发时序的依赖,大幅提升并行的开发效率,理论上允许随时加入新成员认领组件开发或维护工作,也更容易支持多个团队共同维护一个大型站点的开发。
结合前面提到的模块化开发,整个前端项目可以划分为这么几种开发概念:
名称 | 说明 | 举例 |
---|---|---|
JS模块 | 独立的算法和数据单元 | 浏览器环境检测(detect),网络请求(ajax),应用配置(config),DOM操作(dom),工具函数(utils),以及组件里的JS单元 |
CSS模块 | 独立的功能性样式单元 | 栅格系统(grid),字体图标(icon-fonts),动画样式(animate),以及组件里的CSS单元 |
UI组件 | 独立的可视/可交互功能单元 | 页头(header),页尾(footer),导航栏(nav),搜索框(search) |
页面 | 前端这种GUI软件的界面状态,是UI组件的容器 | 首页(index),列表页(list),用户管理(user) |
应用 | 整个项目或整个站点被称之为应用,由多个页面组成 |
以上5种开发概念以相对较少的规则组成了前端开发的基本工程结构,基于这些理念,我眼中的前端开发就成了这个样子:
示意图 | 描述 |
---|---|
整个Web应用由页面组成 | |
页面由组件组成 | |
一个组件一个目录,资源就近维护 | |
组件可组合, 组件的JS可依赖其他JS模块, CSS可依赖其他CSS单元 |
综合上面的描述,对于一般中小规模的项目,大致可以规划出这样的源码目录结构:
如果项目规模较大,涉及多个团队协作,还可以将具有相关业务功能的页面组织在一起,形成一个子系统,进一步将整个站点拆分出多个子系统来分配给不同团队维护。
三、规范化
模块化和组件化确定了开发模型,而这些东西的实现就需要规范去落实。规范化其实是工程化中很重要的一个部分,项目初期规范制定的好坏会直接影响到后期的开发质量。
我能想到的有以下一些内容:
·目录结构的制定
·编码规范
·前后端接口规范
·文档规范
·组件管理
·Git分支管理
·Commit描述规范
·定期CodeReview
·视觉图标规范
其中编码规范最好采取ESLint和StyleLint等强制措施,因为人是靠不住的,比如可以Lint通不过不能提交代码等。
四.自动化
作了这么多年程序猿的我,一直秉持的一个理念是:任何简单机械的重复劳动都应该让机器去完成。所以我也认为,前端工程化的很多脏活累活都应该交给自动化工具来完成。
①图标合并
·不要再用PS拼雪碧图了,有Gulp+SpriteSmith;
·不要再用Icomoon了,这仍然是半自动的,有FontCustom。
②持续集成
③自动化构建
④自动化部署
⑤自动化测试
前端自动化测试能够提高代码质量、减少人肉测试等,这些优点是不言而喻的。市面上前端测试框架有很多,选择哪个都不会有太大问题,我们用的是:Karma + Mocha + Chai
⑥构建工具
最后就是你的团队可能不只一个项目,如果每个项目都搭一套gulp+webpack+babel+...,维护成本比较高,而且不能保证统一性。
因此基于Gulp实现一套独立于项目的构建工具是最好的解决方案。可以参考一下我们网易蜂巢的构建工具rainfore/pursuit-cli,开发者只要会用pursuit dev和pursuit online两句命令就行。
参考资料:https://github.com/fouber/blog/issues/10
参考资料:https://www.zhihu.com/question/24558375
posted on 2017-04-11 01:03 jacksplwxy 阅读(248) 评论(0) 编辑 收藏 举报