目前来说,web 业务日益复杂化和多元化,前端开发从 WebPage 模式为主转变为 WebApp 模式为主了。前端的开发工作在一些场景下被认为只是日常的一项简单工作,或只是某个项目的"附属品",并没有被当做一个"软件"而认真对待(无论是产品负责人还是开发者)。
在模式的转变下,前端都已经不是过去的拼几个页面和搞几个 jq 插件就能完成。当工程复杂就会产生许多问题,比如:
前端工程化是使用软件工程的技术和方法来进行前端的开发流程、技术、工具、经验等规范化、标准化,其主要目的为了提高效率和降低成本,即提高开发过程中的开发效率,减少不必要的重复工作时间,而前端工程本质上是软件工程的一种,因此我们应该从软件工程的角度来研究前端工程。
"前端工程化"里面的工程指软件工程,和我们一般说的工程是两个完全不同的概念。
如何做"前端工程化"?
前端工程化就是为了让前端开发能够“自成体系”,个人认为主要应该从模块化、组件化、规范化、自动化四个方面思考。
简单来说,模块化就是将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载。
在 ES6 之前,JavaScript 一直没有模块系统,这对开发大型复杂的前端工程造成了巨大的障碍。对此社区制定了一些模块加载方案,如 CommonJS、AMD 和 CMD 等。
现在 ES6 已经在语言层面上规定了模块系统,完全可以取代现有的 CommonJS 和 AMD 规范,而且使用起来相当简洁,并且有静态加载的特性。
Webpack
+ Babel
将所有模块打包成一个文件同步加载,也可以搭乘多个 chunk
异步加载;System
+ Babel
主要是分模块异步加载;<script type="module">
加载。虽然 SASS、LESS、Stylus 等预处理器实现了 CSS 的文件拆分,但没有解决 CSS 模块化的一个重要问题:选择器的全局污染问题。
按道理,一个模块化的文件应该要隐藏内部作用域,只暴露少量接口给使用者。而按照目前预处理器的方式,导入一个 CSS 模块后,已存在的样式有被覆盖的风险。虽然重写样式是 CSS 的一个优势,但这并不利于多人协作。
为了避免全局选择器的冲突,需要制定 CSS 命名风格:
但是这毕竟是弱约束。所以很赞同一句话:
与其费尽心思地告诉别人要遵守某种规则,以规避某种痛苦,倒不如从工具层面就消灭这种痛苦。
从工具层面,社区又创造出 Shadow DOM、CSS in JS 和 CSS Modules 三种解决方案。
Webpack 的强大之处不仅仅在于它统一了 JS 的各种模块系统,取代了 Browserify、RequireJS、SeaJS 的工作。更重要的是它的万能模块加载理念,即所有的资源都可以且也应该模块化。
资源模块化后,优点是:
从 UI 拆分下来的每个包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元,我们称之为组件。
组件化 ≠ 模块化。模块化只是在文件层面上,对代码或资源的拆分;而组件化是在设计层面上,对 UI(用户界面)的拆分。
其实,组件化更重要是一种分治思想。
Keep Simple. Everything can be a component.
页面上所有的东西都是组件。页面是个大型组件,可以拆成若干个中型组件,然后中型组件还可以再拆,拆成若干个小型组件,小型组件也可以再拆,直到拆成 DOM 元素为止。DOM 元素可以看成是浏览器自身的组件,作为组件的基本单元。
传统前端框架/类库的思想是先组织 DOM,然后把某些可复用的逻辑封装成组件来操作 DOM,是 DOM 优先;而组件化框架/类库的思想是先来构思组件,然后用 DOM 这种基本单元结合相应逻辑来实现组件,是组件优先。这是两者本质的区别。
其次,组件化实际上是一种按照模板(HTML)+样式(CSS)+逻辑(JS)三位一体的形式对面向对象的进一步抽象。
所以我们除了封装组件本身,还要合理处理组件之间的关系,比如 (逻辑)继承、(样式)扩展、(模板)嵌套和包含等,这些关系都可以归为依赖。
目前市面上的组件化框架很多,主要的有 Vue、React、Angular。Vue 文档中的对比其他框架一文已经讲得很详细了。
规范化其实是工程化中很重要的一个部分,项目初期规范制定的好坏会直接影响到后期的开发质量。
比如:
目录结构的合理设定,能为项目带来很多优点:
制定一套良好的编码规范可以增强团队开发协作、提高代码质量。 推荐参考凹凸实验室打造的前端代码规范。
编码规范包括
基于 W3C、苹果开发者 等官方文档,并结合团队业务和开发过程中总结的规范约定,让页面 HTML 代码更具语义性。
统一规范团队 CSS 代码书写风格和使用 CSS 预编译语言语法风格,提供常用媒体查询语句和浏览器私有属性引用,并从业务层面统一规范常用模块的引用。
统一规范团队 CSS 代码书写风格和使用 CSS 预编译语言语法风格,提供常用媒体查询语句和浏览器私有属性引用,并从业务层面统一规范常用模块的引用。
了解各种图片格式特性,根据特性制定图片规范,包括但不限于图片的质量约定、图片引入方式、图片合并处理等,旨在从图片层面优化页面性能。
从 目录、图片、HTML/CSS 文件、ClassName 的命名等层面约定规范团队的命名习惯,增强团队代码的可读性。
“基于 Ajax 带来的 SPA 时代”,这种模式下,前后端的分工非常清晰,前后端的关键协作点是 Ajax 接口,引发一个重要问题:前后端的对接界面双方却关注甚少,没有任何接口约定规范情况下各自撸起袖子就是干,导致我们在产品项目开发过程中,前后端的接口联调对接工作量占比在 30%-50%左右,甚至会更高。往往前后端接口联调对接及系统间的联调对接都是整个产品项目研发的软肋。
接口规范主要初衷就是规范约定先行,尽量避免沟通联调产生的不必要的问题,让大家身心愉快地专注于各自擅长的领域。
那么,对于这一 SPA 阶段,前后端分离有几个重要的关注挑战:
前后端仅仅通过异步接口(AJAX/JSONP)来编程; 前后端都各自有自己的开发流程,构建工具,测试集合; 关注点分离,前后端变得相对独立并松耦合。
后端 | 前端 |
---|---|
提供数据 | 接收数据,返回数据 |
处理业务逻辑 | 处理渲染逻辑 |
接口返回数据即显示,前端仅做渲染逻辑处理; 渲染逻辑禁止跨多个接口调用; 前端关注交互、渲染逻辑,尽量避免业务逻辑处理的出现; 请求响应传输数据格式:JSON,JSON 数据尽量简单轻量,避免多级 JSON 的出现;
响应基本格式及处理状态值的规范。 基本响应格式 列表响应格式 特殊内容 下拉框、复选框、单选框统一由后端逻辑判定选中返回给前端展示; 关于 Boolean 类型,JSON 数据传输中一律使用 1/0 来标示,1 为是/True,0 为否/False 关于日期类型,JSON 数据传输中一律使用字符串,具体日期格式因业务而定;
文档规范
组件管理
git 分支管理
commit 描述规范
视觉图标规范
...
前端工程化的很多脏活累活都应该交给自动化工具来完成。需要秉持的一个理念是:
任何简单机械的重复劳动都应该让机器去完成。
图标合并
持续集成
自动化构建
自动化部署
自动化测试
参考: 前端工程化的理解