购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.4 前端工程化

虽然前端工程化是最近几年才兴起的一个方向,但工程化并不是一个新词。前端工程师普遍不熟悉的其他开发领域很早就具备了高度的工程化,比如Web服务器端开发。在前端业务逻辑比较简单的年代,前端资源通常作为服务器端资源的一种“附属品”,Web 开发者没有意识到且也没有必要为前端制定专门的工程化方案。前端需求和逻辑的不断加重是催生前端工程化的环境因素,前端相关技术、规范和工具的发展是前端工程化得以实施的必要前提。

1.4.1 前端工程化的衡量准则

前端工程化的主要目标是解放生产力、提高生产效率。通过制定一系列的规范,借助工具和框架解决前端开发以及前后端协作开发过程中的痛点和难点问题。

1.3节我们从开发、测试和部署3个角度分析了前后端分离对于工作效率的提升,既然前后端分离是前端工程化方案的指导方针,这三者也就成为衡量前端工程化方案是否合格的重要因素。具体的衡量标准就是我们常说的3个字:快、准、稳。

1.从开发角度衡量工程化主要体现在“快”。

开发速度是Web产品迭代最迫切提升,也是催生开发人员与产品经理、项目经理以及测试人员之间矛盾的主要因素,自然也是衡量前端工程化方案最直观、最明显的标准。工程化方案的核心目标之一就是在保证质量的前提下,尽可能提高产品的开发速度。

2.从测试角度衡量工程化主要体现在“快”和“准”。

测试的“快”体现在前端工程师和服务器端工程师并行开发完成之后的集成测试阶段。1.3节从测试角度分析前后端分离时提到了完备且合理的单元测试通过后,集成测试阶段是不应该存在逻辑性错误的。但人不是机器,不可能考虑得面面俱到。从这个角度考虑,工程化要解决的就是尽量减少低级的逻辑错误,降低集成测试阶段消耗的时间成本。

测试的“准”体现在集成测试阶段对问题的准确定位。1.3节我们提到了,工程化不仅仅是冷冰冰的工具和平台,同时也需要严格的分工制度。通过明确责任人,对测试出现的问题进行快速准确的定位。

3.从部署角度衡量工程化主要体现在“稳”。

部署是一个完整迭代周期的最终阶段。经历了漫长的开发和测试,团队中的所有成员都希望自己的产品能够第一时间完美无误地出现在用户面前。部署并不是简单地把文件“放到”线上就可以了,还需要考虑用户客户端的缓存是否影响了新版本的展现、考虑测试用例没有覆盖100%情况下的危机处理、考虑不同地区开放不同版本等。如果你想将Web产品稳稳地呈现给用户,部署环节必须把好最后也是最关键的一关。

1.4.2 前端工程化的进化历程

市场需求和技术的发展在不断地改变Web产品形态,在前端工程师的工作内容不断变化的过程中,前端工程化的形态也一直都在变化着。

1.混沌形态

我们不妨将这种“前端写demo,后端写逻辑、套模板”的开发模式称为“混沌形态”。这种形态的时代背景是Web产品的逻辑和交互普遍比较简单,前端工程师这一专业岗位刚刚兴起,但是负责的工作仅仅是样式以及部分动画逻辑。前端工程师与后端工程师之间的协作是串行的,如图1-5所示。

混沌形态下前端工程师的产出资源除了CSS外,均需要后端工程师进行二次处理后才会上线,甚至有时候连CSS都需要二次处理,比如行内样式。这种形态下是没有前端工程化可言的。

图1-5

2.前后端分离形态

催动前端开发第一次进化的关键技术是 AJAX。AJAX 技术的问世不仅改变了Web页面的交互模式,也间接提高了用户对Web产品的需求,从而促进了前端逻辑的不断复杂化。服务器端工程师负责前端逻辑开发的混沌形态被打破,因为服务器端逻辑本身便具备高度的复杂度,再加上复杂的前端逻辑,自然不堪重负。所以,工程师开始思考改变原有的分工模式:前端逻辑、样式和HTML全部交由前端工程师开发。这是催生前端工程化萌芽的关键一步,此时的协作流程如图1-6所示。

图1-6

在这种分工模式下,省去了后端工程师对JavaScript代码的整合以及对CSS代码的二次处理工作,从一定程度上提升了维护和迭代的工作效率。但是因为静态资源与动态资源一同部署,所以仍然难以避免必要的人工交付流程。

我们设想一下将这种分工模式带入当前时间节点,这时开发过程中会遇到哪些问题。

1)我们想使用最新的ECMAScript规范进行开发,但是受限于浏览器实现不理想,上线前需要使用特殊工具转译为浏览器支持的语法。

2)我们受够了CSS的弱编程能力,想使用LESS/SASS等预编译语法或者PostCSS自动处理hack。但是浏览器不支持,上线前需要使用特殊工具进行编译转换。

3)本地开发环境下静态资源的引用 URL 都是本地相对地址,上线前要修改为真实的 URL。手动修改非常烦琐,需要借助工具完成。这种功能通常被称为资源定位。

4)考虑产品的性能,上线前需要将JS、CSS、图片等资源进行压缩,需要使用CSS Sprites,甚至需要将小体积图片通过base64格式内嵌,这些都需要借助于工具实现。

5)模块化开发能够提高Web产品的性能和源代码的维护效率,散列的模块在上线前需要进行依赖分析与合并打包,需要借助于工具实现。

6)编写 JavaScript 逻辑代码时如果需要与数据接口交互,则依赖于服务器端接口API的完成进度。

7)静态文件(JS、CSS、图片等)与动态文件(HTML 模板)仍然存在于同一项目中,所以前端工程师产出的文件仍然需要服务器端工程师进行部署。

小贴士: 此处列出的只是一些比较典型的问题,并未覆盖前后端开发以及协作过程中的全部问题。

将上述问题进一步划分:前5条因为不存在前后端的耦合,可以归类为前端开发层面的问题;第6条属于前后端协作的问题;第7条属于部署的问题。细化分类后的问题列表如下。

● 开发层面

ES规范与浏览器兼容性不一致。

CSS的弱编程能力。

资源定位。

图片压缩/base64内嵌/CSS Sprites。

模块依赖分析和压缩打包。

● 协作层面

JavaScript部分逻辑依赖接口API。

● 部署层面

部分资源需要借助后端工程师部署。

笔者相信大多数一线开发者最迫切要解决的问题普遍集中在开发层面。在开发层面问题的描述中反复提到一个词——工具。开发者采用各种各样的专业工具解决对应的需求,比如使用Babel进行ES规范的转译、使用LESS/SASS编译工具进行预编译语法转译、使用r.js解决AMD模块的压缩打包等。将所有工具的功能进行整合并统一为规范的工具栈(请注意不是将工具整合,而是将功能整合),这就是前端工程化的第一步:构建。

第一步:加入构建流程

引入构建后的工作流程如图1-7所示。

图1-7

构建流程可以确保前端工程师能够使用有助于提高开发和维护效率的框架、规范进行源代码的编写,比如使用 ECMAScript 6/7 规范编写 JavaScript、使用LESS/SASS等预编译工具编写Style、使用AMD/CommonJS等模块化方案进行模块化开发等。此外,构建还具备图片压缩、自动生成CSS Sprites等功能,进一步减少了烦琐的人工操作。

前端工程化进化到第一步后解决了开发层面的问题,会提高前端工程师的开发效率,但是仍未触及协作以及部署层面。

● 开发层面

ES规范与浏览器兼容性不一致。

CSS的弱编程能力。

资源定位。

图片压缩/base64内嵌/CSS Sprites。

模块依赖分析和压缩打包。

● 协作层面

JavaScript部分逻辑依赖接口API。

● 部署层面

部分资源需要借助后端工程师部署。

构建流程的加入提高了前端工程师单方面的工作效率,下一步是思考如何提高整体团队的效率,也就是在前后端协作开发过程中遇到的问题。最典型的就是前端逻辑依赖后端接口的实现进度,这种串行的工作流程对于开发进度的影响是非常大的。所以,接下来首当其冲的便是解决前后端工程师并行开发的问题。

第二步:加入本地开发服务器

本地开发服务器并不是工具,而是一个真正意义上的Web服务。本地服务器最典型的应用是Mock服务,通过提供模拟接口和数据解决前端JavaScript对数据API的依赖问题,从而实现前后端并行开发,前提是前后端工程师在进入开发阶段之前需要协商制定接口API的详细规范。

对于一些有云Mock服务器的团队来讲,本地服务器甚至可以不提供Mock服务。但是如果项目需要SSR(Server Side Render,服务器端渲染)并且本地服务器与服务器端使用相同的编程语言,本地服务器还应该具备HTML模板解析功能。这样,前端工程师负责View层的开发工作,后端工程师负责服务器端逻辑开发。这种模式对Mock服务有了额外的需求——提供服务器端渲染的页面初始数据。云Mock平台是无法完成此项功能的,这是本地 Mock 服务独有的优势。所以,不论项目是否需要SSR,我们都建议将Mock服务集成到本地开发服务器。即使你的团队有云Mock服务,本地的Mock服务也可以使用代理模式将请求转交给云Mock服务。

由于所有的客户端相关资源(包括Views)均交由前端工程师负责开发,后端工程师不需要对前端工程师产出的文件进行二次处理,只进行一次支付便可部署,因此可以使用Git、SVN等版本管理工具替代人工交付,对代码回滚提供了更严谨的技术支持。

此外,本地服务器与构建功能相结合,可以提供动态构建、浏览器自动刷新等功能,这进一步提高了前端工程师的工作效率。

综上所述,本地服务器须具备以下功能。

● Mock 服务。如果团队具备统一的云 Mock 平台,本地服务器可以不提供Mock服务。但如果需要支持SSR,则必须提供本地Mock服务。

● 支持SSR,前提是本地服务器与线上服务器使用相同的编程语言。

● 动态构建,浏览器自动刷新。

引入本地服务器后的开发流程如图1-8所示。

图1-8

加入本地服务器后的问题情况如下。

● 开发层面

ES规范与浏览器兼容性不一致。

CSS的弱编程能力。

资源定位。

图片压缩/base64内嵌/CSS Sprites。

模块依赖分析和压缩打包。

● 协作层面

JavaScript部分逻辑依赖接口API。

● 部署层面

部分资源需要借助后端工程师部署。

前端工程化发展到这个阶段,我们解决了开发以及协作层面的问题,留到最后的只有部署了。

第三步:静态资源和动态资源分离部署

我们设想一下这种场景:前端代码中出现了Bug,前端工程师修复后仍需要麻烦后端工程师进行部署。前端的Bug有时候可以细微到像素级别,即使再小的Bug也需要调动前后端工程师来修复,这样的工作效率是非常低下的。所以优化部署的基本原则是,确保单方问题的修复不需要调动多方资源。具体的解决方案就是静态资源与动态资源分离部署。动静态资源的分离部署可以解耦前后端工程师的部署行为,两者可以对自身的产出进行独立部署。减少了耦合工作,就提高了迭代和维护效率。同时,动静态资源分离部署也是Web应用架构优化的一个必要策略。

分离部署对工作效率的提升主要体现在集成测试阶段。比如测试人员发现浏览器有样式Bug,在前端工程师修复并将CSS文件部署到测试文件服务器后便可以立即进行 Bug 修复验证测试,不涉及后端工程师的工作。前提是测试所用的静态资源服务器需要设置浏览器不使用缓存或者协商缓存策略,并且静态资源的URL不添加版本号参数或者hash文件指纹,这样在静态文件更新后刷新浏览器即可请求到最新的文件,无须清理浏览器缓存。同理,只涉及服务器端代码的 Bug 修复也不涉及前端工程师的工作。

小贴士: 第3章将详细讲解不同缓存策略的区别以及各自的优缺点。

我们不妨再激进一点:将渲染HTML的工作全部交给前端,也就是目前业界流行的SPA(单页应用)。前端渲染的优点如下。

● 前端掌控路由,与传统的服务器端路由相比用户体验更佳。

● 可移植、可离线使用。

● 服务器端提供的是干净的数据接口,具备高度的可复用性。

● HTML资源作为静态资源,易于部署。

● 前端工程师与后端工程师可以使用 Git、SVN 等工具分别维护独立的源代码,无须耦合。

前端渲染的缺点是不利于SEO(搜索引擎优化)。Google搜索爬虫制定了针对单页应用的优化规范,国内的搜索引擎目前暂未提供类似规范。即便如此,SPA 仍然在业界被广泛使用,其主要原因是Web产品已经改变了原有的形态。自身功能和宿主浏览器的不断增强让Web产品越来越接近原生应用,对SEO不像以前那般依赖。另外,越来越多的Hybrid(混合)应用占据了APP市场,由WebView承载的Web产品更是无须考虑SEO问题。

在上一阶段的前端工程化基础上,加入静态资源与动态资源分离部署功能后的前后端协作流程如图1-9所示。

图1-9

加入静态资源与动态资源分离部署功能后,一方面提高了部署的效率,另一方面也提高了Bug的修复效率。需要注意的一点是,如1.3节所述的html文件必须使用协商缓存策略,便于线上资源的及时更新。我们再回顾一下上文提到的问题列表。● 开发层面

ES规范与浏览器兼容性不一致。

CSS的弱编程能力。

资源定位。

图片压缩/base64内嵌/CSS Sprites。

模块依赖分析和压缩打包。

● 协作层面

JavaScript部分逻辑依赖接口API。

● 部署层面

部分资源需要借助后端工程师部署。

前端工程化发展到这一阶段,所对应的前后端分离工作模式是目前国内绝大部分团队所采用的。本书所讨论的前端工程化解决方案便是针对这种模式搭建的。

小贴士: 这种模式下的前后端分离并非完美,前后端工程师的分工也并非最合理,此阶段的前端工程化并非最终形态。我们将在第7章深入讨论前端工程化的理想模式。

1.4.3 前端工程化的3个阶段

1.本地工具链——工程化不等同于工具化

上文对前端工程化的描述可能会令你产生这样一个念头:所谓的前端工程化不就是把一系列工具进行整合吗?工程化的核心难道就是工具化?

虽然我们的论述中反复提到了“工具”这个词,但工程化的核心并非工具。前端工程化是以规范工作流程为手段,以工具为实现媒介,其最终目的是为了提高研发效率以及保证Web产品的线上质量。如果给前端工程化一个明确定义的话,较恰当的定义如下:前端工程化是一系列工具和规范的组合,规范为蓝本,工具为实现。其中规范又包括:

● 项目文件的组织结构,比如使用目录名称区分源文件和目标文件。

● 源代码的开发范式,比如使用既定的模块化方案。

● 工具的使用规范,比如工程化自身的配置规范。

● 各阶段环境的依赖,比如部署功能的实现需要目标服务器提供SSH权限。

工具的作用是将规范具化为具体功能并且在一定程度上将开发者限定在既有规范内。前端工程化的初级阶段便是将各类工具的功能进行整合,为业务开发人员提供统一规范的工具栈。我们不妨将此阶段的前端工程化称为本地工具链形态。此形态下的所有工程化功能模块,包括构建、本地服务器、部署等,均在本地环境下工作。

本地工具链形态的工程化方案解决的问题,降低了业务开发人员学习、使用工具的成本。这个方案将复杂的功能需求全部交给工具链内部解决,你可以将这个形态的方案想象成一只拥有高度内部复杂度的“八爪鱼”,其伸出的触手是内部功能开放给业务开发人员使用的接口。

工具链的统一,另一个好处是巩固了流程的规范性,开发者使用统一的工具链、遵循统一的规范进行业务代码的编写,利于多人协作与程序的维护。

2.管理平台——进一步淡化差异、加深规范

本地工具链形态的工程化虽然解决了前端开发以及前后端协作开发中的部分痛点问题,但由于所有的功能模块均在本地环境工作,因此必然会受到环境差异性的影响,比如操作系统类型、版本、内核等。这些因素会在一定程度上影响构建产出代码的一致性。

除环境因素的影响,本地工具链形态的工程化还存在安全性隐患。举个例子,部署功能模块负责将构建产出的文件部署到测试或者线上服务器,部署过程中必然涉及权限问题。对安全性要求不高的测试环境也就罢了,但如果人人都可以向生产环境部署文件则必然存在很大的安全隐患。所以,权限必须严格控制,这就造成本地工具链的部署模块的可用性大大降低。

讲到这里,前端工程化的下一进化形态便豁然开朗了:集中管理的云平台。管理平台形态的工程化做到了以下几点。

● 淡化环境差异性,保证构建产出的一致性。

● 权限集中管理,提高安全性。

● 项目版本集中管理,便于危机处理,比如版本回滚等。

管理平台形态将各个功能模块的执行环境集中化,从各模块实现角度来讲与本地工具链基本一致。

3.持续集成——前端工程化的目标是融入整体

即使进化到管理平台形态,前端工程化方案所解决问题的本质仍然只是将前端工程师与服务器端工程师的工作解耦。这虽然提高了两方的工作效率,但其各自的工作流却是孤立的。前端有了构建和部署,后端也有了相应的阶段,两方的工作流是分离的,最终的融合工作仍然难以避免烦琐的人工操作。举个例子,如果需要生产环境版本回滚,前后端工程师分别对自己所维护的代码进行操作,并且必须保证回滚操作的同步性,这期间难以避免人工上的沟通。

不论前端工程化的功能如何完备,规范如何严谨,需要谨记的是,前端工程化必然是整体Web工作流中间的一个子集方案。前端工程化最终的完美形态,必然与整体工作流结合,作为持续集成方案中的一环。谨记这条原则可以在探索完美方案过程中少走弯路。 +7KRxgIzyzrQXl5t+HW+0penKwbCE4dQkLQjFIFt2/0ttphDJ0+SpunC+fE9My0X

点击中间区域
呼出菜单
上一章
目录
下一章
×