前端架构的工程化

671 阅读6分钟

此文写于2019年,2022年2月对外同步。此文的内容集成了各博客、优质文章内容,若有侵权,请联系删除。

近两年前端领域风云变幻,各种技术栈层出不穷。React、Angular、Vue 逐步三分天下,Webpack + Babel + ES6 模式如日中天,PostCSS 大有取代 SASS、LESS、Stylus 的趋势,还有 HTTP2、WebComponents、WebAssembly、函数式编程等新概念不断涌现。让前端工程师应接不暇、感叹不已:“今年一个技术还没学会,明年可能就不用学了。”

回顾前端发展历史,按照《前端开发技术的发展》一文中的观点,大概可以分为三个阶段:

  • 刀耕火种:典型特征是服务器语言(ASP、JSP、PHP)为主,结合简单的 CSS 和 JS 代码片段。是最早期的 WebPage 模式;

  • 手工工场:典型特征是 Ajax 的出现,它使得 WebApp 模式成为可能。这期间 jQuery、Prototype 和 Mootools 几个库占主导地位,并出现了初步的模块加载方式;

  • 工业革命:典型特征是各种 MV*框架的不断出现,各种开发模式的不断演进,各种自动化工具的不断革新,各种标准的不断确立。

2015 年 ES6 标准的确立标志着前端领域正式进入了蒸汽时代。但离流水线作业的电气时代还有一段路要走。

相对于去年剧烈的变革,今年的前端生态有所缓和。乘着工业化浪潮,ADA 前端本着面向未来、稳步推进的原则,也对项目架构进行了优化改进,并确立了新的发展方向。

关于前端架构的工业化,主要应该从模块化、组件化、规范化和自动化四大方面考虑,下面一一展开:

模块化

分工产生效能

模块化是“刀耕火种”和“手工工场”的分界线。它的作用是将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载,这为多人协作提供了可能。

JS 的模块化

在 ES6 之前, 社区制定了一些模块加载方案,如 CommonJS、AMD 和 CMD 等, 这对开发大型复杂的前端工程造成了巨大的障碍。ES6 已经在语言层面上,规定了模块系统,而且使用起来相当方便,完全可以取代现有的 CommonJS 和 AMD 规范。

如果你想使用 ES6:

  • IE6、7 就不用考虑了;
  • IE8在项目中不能使用export * from 'xxx'这个功能,但不能保证使用的依赖库中没有用到,具体请参考使React 应用兼容 IE8
  • IE9+ 只需吃个 babel-polyfill 就能完美使用

打包工具,目前来说最好的非 Webpack 莫属。因此,技术选型:Webpack + Babel + ES6

CSS 的模块化

虽然 SASS、LESS、Stylus 等预处理器实现了 CSS 的文件拆分,但没有解决 CSS 模块化的核心问题:选择器的私有化问题(全局污染问题)。 为了避免全局选择器的冲突,各厂都制定了自己的 CSS 命名风格:

  • BEM 风格;
  • Bootstrap 风格;
  • Semantic UI 风格;
  • ...

与其费尽心思地告诉别人要遵守某种规则,以规避某种痛苦,倒不如从工具层面就消灭这种痛苦。

从工具层面,社区又创造出 Shadow DOM、CSS in JS 和 CSS Modules 三种解决方案:

  • Shadow DOM 是 WebComponents 的标准。它能解决全局污染问题,但也使样式彻底私有化了,造成外部无法重写,损失了灵活性;

  • CSS in JS 是彻底抛弃 CSS,使用 JS 或 JSON 来写样式。这种方法很激进,不能利用现有的 CSS 技术,而且处理伪类等问题比较困难;

  • CSS Modules 仍然使用 CSS,只是让 JS 来管理依赖。它能够最大化地结合 CSS 生态和 JS 模块化能力,目前来看是最好的解决方案。

技术选型:PostCSS + CSS Modules(或 Scoped CSS)。

组件化

现代化生产的分工协作要求工业部件遵循互换性原则。

组件系统.jpg

当前最火的 React 带头掀起了组件化浪潮,随后 Vue、Polymer、Angular2 等各种组件化框架 / 类库如雨后春笋般出现。

组件化的概念

组件化≠模块化

  1. 模块化只是在语言层面上,对代码的拆分;而组件化是基于模块化,在设计层面上,对 UI(用户界面)的拆分。

    从 UI 拆分下来的每个包含模板 (HTML)+ 样式 (CSS)+ 逻辑 (JS) 功能完备的结构单元,我们称之为组件,这其实是一种分治(分而治之)思想。

  2. 组件化是一种在设计层面上,对项目中 UI 进行整体的疏理和拆解,再按照 HTML+CSS+JS 三位一体的面向对象来进行封装的过程或思想。

    比如 Vue 的*.vue 单文件结构

    vue单文件.png

  3. 组件系统它提供了一种抽象,让我们可以用独立可复用的小组件来构建大型应用。
    如果我们考虑到这点,几乎任意类型的应用的界面都可以抽象为一个组件树:

    组件系统.png

组件的分类

按照组件的代码组成,组件可以分为:HTML、HTML+CSS、JS、HTML+JS、HTML+CSS+JS。

按照组件的通用性(复用性),组件可以分为以下三类:

  • 通用组件:不同产品间可以复用的组件。
  • 通用业务组件:仅在同一产品中可以复用的组件。
  • 业务组件:不可以复用的组件。比如具体场景中使用的组件,一次性的业务模块等。

组件的一个设计原则是:在不增加组件配置复杂度的情况下,尽可能的提高组件通用性。

组件之间的关系

组件之间的关系有继承、扩展和嵌套,还有包含,表示一个组件内部调用了另一个组件。这些关系都可以归属为依赖。

组件库

组件库是一系列组件的集合。 如Element-UIANT DESIGN等等

规范化

现代工厂制度是工业革命发展的必然产物。

模块化和组件化确定了开发模型,而这些东西的实现需要规范去落实,如:

  • 目录结构:源文件和目标文件完全分开,依赖统一用 npm 进行包管理。
  • 编码规范:JS/CSS Lint

自动化

现代工业其所以区别于工场手工业,是由于机器起了主要的作用。自动化是“手工工场”和“工业革命”的分水岭。

  1. 静态资源合并:图标合并(雪碧图、字体图标);JS、CSS 代码合并压缩

  2. 可视化组件文档:前端开发和后端开发不同的是,前端开发是可视化的。组件示例和文档内容,可参考上面提到的几个组件库的文档。

  3. 前端自动化测试
    遵循维护自动化测试成本最低原则,在项目中只覆盖:
    a、基础类库的单元测试;
    b、通用组件和通用业务组件的单元测试;
    c、通用组件和通用业务组件简单的 UI 测试。
    d、必要的 e2e 测试

技术选型:Karma + Mocha Jest、TestCafe (2022 年修改)

构建工具

目前 Gulp 是处理工作流的最佳选择,没有之一。 条件允许建议使用 vite 等 bundleless 构建工具,

不过构建项目各阵营均有自己的脚手架:Vue-clicreate-vuegithub.com/vuejs/creat…](www.npmjs.com/package/rea…](github.com/angular/ang…)

包管理工具

NPMYarnpnpm