当前位置:网站首页 > 前端开发 > 正文

前端工程化工具包括哪些(前端工程化工具包括哪些内容)



2. 脚手架

2.1 脚手架的功能和本质

脚手架一词最早来源于建筑工程领域,是一种辅助工程建设的临时性设施。引申到软件开发领域,脚手架作为一种创建项目初始文件的工具被广泛地应用于新项目或者迭代初始阶段。

使用工具替代人工操作能够避免人为失误引起的低级错误,同时结合整体前端工程化方案,快速生成功能模块配置、自动安装依赖等,降低了时间成本。

Eclipse创建项目的流程就是一个典型的脚手架工作流:

Eclipse创建项目的流程是一个“两头窄中间宽”的形象。选择项目类型是入口,随后一系列复杂的树形配置项,配置完毕之后将所有配置项进行汇总,最终创建项目文件完成整个流程。

整个流程可以简单归纳为:选定方案、配置方案细节、配置完成、根据定制方案创建项目文件、结束流程。

由此,我们便明确了脚手架的功能和本质:脚手架的功能是创建项目初始文件,本质是方案的封装。

2.2 脚手架在前端工程中的角色和特征

不同于Java、Android等存在固定模式和技术选型的项目,前端项目的资源类型多样、技术选型宽泛、工作流程无固定规范等一系列特征造成前端脚手架与Eclipse脚手架相比存在一定的差异性和独特性。

2.2.1 用完即弃的发起者角色

下图是一个简化版的前端工程工作流:

一个功能完备、设计合理、提供丰富配置项的脚手架工具,最终的目的是为了得到项目初始文件,创建完成项目初始文件之后,脚手架就再也没有用武之地了。

前端工程体系涵盖功能广泛、封装方案类型众多,对应的配置项也非常复杂。大多数前端工程方案和相关工具的开发者并不负责一线业务开发。

对于业务开发人员来说,前端工程方案和工具就是一个黑盒,不需要了解其中的复杂原理,只需要知道如何配置、如何使用即可。

前端工程体系不是Vue、React这种业务开发框架,工程体系是一种“服务”,是辅助性质的,其服务的主要对象就是一线的业务开发人员。

合理的前端工程体系必须具备的要素之一便是平缓的学习曲线,即使文档再清晰易懂,也不应该强制要求业务开发人员花时间学习各种细节。

业务开发人员需要了解的应该仅仅是如何配置、如何使用,这便是脚手架工具要解决的最切实的问题:

1)快速生成配置;

2)降低框架学习成本;

3)令业务开发人员关注业务逻辑本身。

2.2.2 局限于本地的执行环境

前端工程化的3个阶段:本地工具链、云管理平台和持续集成。三者最明显的外在差异在于,对各个功能模块执行环境的划分。

执行环境分为4类:本地环境、集成平台环境、测试环境以及生产环境。

本地环境指的是开发人员的本机环境;

集成平台环境指的是云管理平台或者持续集成平台环境;

测试环境指的是集成测试阶段测试工程师对产品进行仿真模拟测试的特定沙箱环境;

生产环境指的是产品交付给用户的真实环境。

不论前端工程化是简单的本地工具链,还是集大成的持续集成阶段,脚手架的执行环境始终局限于本地,这给脚手架工具带来一个必须解决的问题:操作系统兼容性。

2.2.3 多样性的实现模式

前端项目类型、资源的多样性以及各团队对前端工程师定位的不同造成前端脚手架没有固定的实现模式。不论具体实现模式如何,优秀的脚手架工具遵循的原则是一致的。

从功能实现的角度考量,需要具备:

1)与构建、开发、部署等功能模块联动,在创建项目时生成对应配置项;

2)自动安装依赖模块。

从平台角度考量,需要具备:

1)动态可配置;

2)底层高度可扩展。

从易用性角度考量,需要具备:

1)丰富但不烦琐的配置项;

2)支持多种运行环境,比如命令行和Node.js API;

3)兼容各类主流操作系统。

脚手架与构建功能模块协作如图:

脚手架的可用配置项一部分由项目的类型决定,另外一部分来自工程体系中各个功能模块开放的配置API。项目类型决定的配置项将影响创建的项目文件内容和类型,而工程体系功能模块的配置项将影响生成的各个功能模块配置文件内容。

脚手架的目的之一便是将配置的复杂度以阶梯状呈现给用户,能够让用户循序渐进地适应和学习整套工程体系。所以,各功能模块的配置项不可能全部由脚手架提供给用户,必须有所取舍。

只将开关配置项交由脚手架开放给用户,细节配置项保持默认值。如果用户有更细化的需求,可以直接修改功能模块的配置文件。

2.3 开源脚手架案例剖析

2.3.1 Sails.js--针对服务器端的脚手架方案

Sails.js是一个企业级Node.js全栈框架,服务器端采用MVC架构,使用Grunt搭建前端工作流。

对脚手架工具基本原则的实现程度:

2.3.2 Yeoman--开放的脚手架平台,不封装任何具体方案

Yeoman的slogan是“THE WEB'S SCAFFOLDING TOOL FOR MODERN WEBAPPS”--面向webapp的脚手架工具。

Yeoman不能直接创建项目文件,它提供了一套完整的脚手架开发API,使用这些API可以定制符合自己业务需求的任意脚手架方案。

对脚手架工具基本原则的实现程度:

Yeoman基本具备了一款优秀的脚手架需要具备的所有要素,如果需要开发一个属于自己的脚手架,Yeoman是最好的选择。

2.4 集成Yeoman封装脚手架方案

脚手架创建项目文件的第一步是收集用户的配置信息;然后将这些动态的配置信息转化成静态的文件内容,Yeoman默认使用EJS引擎;动态内容转化完成之后,如果有必要,可以将文件后缀类型修改为目标文件后缀类型,比如Yeoman将*.ejs文件后缀修改为*.js、*.css、*.html等;最后一步便是将生成的文件复制到目标文件夹。

整体流程如图:

3. 构建

3.1 构建功能解决的问题

构建,或者叫作编译,在前端工程体系中的角色是将源代码转化为宿主浏览器可执行的代码,其核心是资源的管理。

构建需要解决的问题可以归纳为3类:

3.1.1 面向语言

前端的产出资源包括JS、CSS、HTML等,分别对应的源代码是:

1)领先于浏览器实现的ECMAScript规范编写的JS代码;

2)LESS/SASS预编译语法编写的CSS代码;

3)Jade/EJS/Mustache等模块语法编写的HTML代码。

以上源代码是无法在浏览器环境下运行的,构建工作的核心是将其转化为宿主可执行代码,分别对应:

1)ECMAScript规范的转译;

2)CSS预编译语法转译;

3)HTML模板渲染。

3.1.2 面向优化

除了语言本身,前端资源的构建处理还需要考虑Web应用的性能因素,构建还包括以下功能:

1)依赖打包:分析文件依赖关系,将同步依赖的文件打包在一起,减少HTTP请求数量;

2)资源嵌入:比如小于10KB的图片编译为base64格式嵌入文档,减少一次HTTP请求;

3)文件压缩:减小文件体积,缩短请求时间;

4)hash指纹:通过给文件名加入hash指纹,以应对浏览器缓存策略。

3.1.3 面向部署

html文件与JS、CSS、图片等资源是引用与被引用的关系,被引用的资源经过构建后通常有以下变动:

1)域名/路径改变:开发环境与线上环境的域名肯定是不同的,不同类型的资源甚至部署于不同的CDN服务器上;

2)文件名改变:经过构建之后文件名被加上hash指纹,内容的改动导致hash指纹的改变。

以上的改动最终会影响html文件对被引用资源的URL改变。所以对html文件的构建工作需要注意在其引用资源URL改变时同步更新,这个功能通常被称为资源定位

3.2 ECMAScript与Babel

Babel的作用简单概括就是将浏览器未实现的ECMAScript规范语法转化为可运行的低版本语法。

Babel的理念:使用高效率的、宿主不支持的语法进行源代码开发,由编译工具将其转化为目标宿主可识别的语法。

将Babel与Webpack结合使用可以搭建更完善的构建功能,以便打造完整的前端工程体系。

babel-loader是Babel官方提供的Webpack插件,使用方法与常规的Webpack loader插件相似,具体的配置细节参考官方文档。

3.3 CSS预编译与PostCSS

CSS全称Cascading Style Sheets(层叠样式表),用来为HTML添加样式,本质上是一种标记类语言。

3.3.1 CSS的缺陷

1)浏览器实现不理想甚至实现方案各一;

2)CSS的弱编程能力。

3.3.2 CSS预编译器

CSS预编译器的工作原理是提供便捷的语法和特性供开发者编写源代码,随后经过专门的编译工具将源代码转化为CSS语法。

CSS的预编译器有SASS、LESS、Stylus等。

CSS预编译器从以下几个方面提升了CSS开发效率:

1)增强编程能力;

2)增强源码可复用性,让CSS开发符合DRY(Don't repeat yourself)的原则;

3)增强源码可维护性;

4)更便于解决浏览器兼容性。

CSS预编译器的核心功能:嵌套、变量、mixin/继承、运算、模块化等。

3.3.3 PostCSS

预编译器语法并非规范的CSS,而是各成一派,由预编译语法编写的源代码不能在任何宿主浏览器中运行。

PostCSS从理念上更接近Babel,鼓励开发者使用规范的CSS原生语法编写源代码,然后配置编译器需要兼容的浏览器版本,最后经过编译将源码转换为目标浏览器可用的CSS代码。

PostCSS提供了丰富的插件用于实现不同场景的编译需求,最常用的比如autoprefixer、Sprites等。

PostCSS并不是另一种CSS预编译器,与SASS、LESS等预编译器也不冲突。PostCSS与Babel的不同之处在于,它所支持的所谓“未来CSS语法”并不是严格的CSS规范,其中大部分语法和特性目前只是CSS4的草案而已。

目前普遍的方案是将CSS预编译与PostCSS综合在一起:

1)使用CSS预编译弥补CSS源码的弱编程能力,比如变量、运算、继承、模块化等;

2)使用PostCSS处理针对浏览器的需求,比如autoprefix、自动CSS Sprites等。

3.4 模块化开发

3.4.1 模块化与组件化

严格来说,组件(component)和模块(module)是两个不同的概念,两者的区别主要体现在颗粒度层面。

简单地讲,模块是一个白盒,侧重的是对属性的封装,重心在设计和开发阶段,不关注运行时逻辑;组件是一个可以独立部署的软件单元,面向的是运行时,侧重于产品的功能性,组件是一个黑盒,内部的逻辑是不可见的。比如一个button是一个模块,一个包含多个button的导航栏是一个组件。

3.4.2 模块化与工程化

模块化是属于架构层面的概念,前端工程化与模块化的关系类似于组装车间与零件。前端工程体系中的构建系统最重要的功能之一便是支持模块化规范并能够将散列的模块构建为利用部署的整合文件。

3.4.3 模块化开发的价值

1)避免命名冲突;

2)便于依赖管理;

3)利用性能优化;

4)提高可维护性;

5)利于代码复用。

3.4.4 前端模块化发展史

1)CommonJS:面向浏览器之外的模块化规范

CommonJS是一种只适用于JavaScript的静态模块化规范,适合Node.js开发,但并不适合浏览器环境,因为:

a. 浏览器环境的前端资源不仅仅是JavaScript,还包括CSS、图片等,CommonJS无法处理JavaScript以外的资源;

b. CommonJS所有模块均是同步阻塞式加载,无法实现按需异步加载。

2)AMD/CMD:着力于浏览器的模块化规范

在CommonJS基础上,AMD/CMD规范扩展了以下功能:

a. 可以处理JavaScript以外的资源;

b. 源码无须编译便可在浏览器环境下运行;

c. 按需异步加载、并行加载;

d. 插件系统。

CommonJS、AMD、CMD三者共同的缺点:

a. 应用场景单一,模块无法跨环境运行;

b. 构建工具不统一,开发者除了需要学习规范本身,还需要学习对应的构建工具;

c. 不同规范的模块无法混合使用,模块可复用性不高;

d. 未来不可期。

3)ES6 Module:规范的静态模块体系

ES6 Module是语言层面的规范,与应用场景无关,所以一个不涉及运行环境的API调用的模块可以在任何场景下运行。然而受限于浏览器的实现程度,目前针对浏览器的模块仍然需要使用构建工具进行编译。

3.4.5 Webpack模块化构建

Webpack支持CommonJS、AMD和ES6 Module模块化规范,可以任选三者中的一种进行源代码开发。

3.5 增量更新与缓存

合理利用缓存是Web性能优化的必要手段,前端工程师所接触的主要是针对客户端浏览器的缓存策略,客户端的缓存可以分为以下两种:

1)利用本地存储,比如LocalStorage、SessionStorage等;

2)利用HTTP缓存策略,其中又分为强制缓存与协商缓存。

其中对于本地存储的利用属于代码架构层面的优化措施,不属于前端工程体系的服务范畴。

HTTP缓存需要服务器配合,比如Apache、Ngnix等服务器软件可以为资源设置不同的HTTP缓存策略。

增量更新是目前大部分团队采用的缓存更新方案,结合HTTP强制缓存策略,既能够保证用户在第一时间获取最新资源,又可以减少网络资源消耗,提高Web应用程序的执行速度。

3.5.1 HTTP缓存策略

浏览器对静态资源的缓存本质上是HTTP协议的缓存策略,其中又可以分为强制缓存和协商缓存。

两种缓存策略都会将资源缓存到本地,强制缓存策略根据过期时间决定使用本地缓存还是请求新资源;协商缓存每次都会发出请求,经过服务器进行对比后决定采用本地缓存还是新资源。

具体采用哪种缓存策略,由HTTP协议的首部(Headers)信息决定:

1)Expires和max-age

Expires和max-age是强制缓存策略的关键信息,两者均是响应首部信息的。

Expires通过指定一个明确的时间点作为缓存资源的过期时间,在此时间点之前客户端将使用本地缓存的文件应答请求,而不会向服务器发出实体请求。

Expires的缺陷:它所指定的时间点是以服务器为准的时间,但是客户端进行过期判断时是将本地的时间与此时间点对比。

针对这个问题,可以使用Cache-control首部信息以便更精准地控制缓存。

常用的Cache-control信息有以下几种:

a. no-cache和no-store

“no-cache”:并非禁止缓存,而是需要先与服务器确认返回的响应是否发生了变化,如果资源未发生变化,则可使用缓存副本从而避免下载;

“no-store”:是真正意义上的禁止缓存,禁止浏览器以及所有中间缓存存储任何版本的返回响应。

b. public和private

“public”:表示此响应可以被浏览器以及中间缓存器无限期缓存,此信息并不常用,一般使用max-age指定精确的缓存时间;

“private”:表示此响应可以被用户浏览器缓存,但是不允许任何中间缓存器对其进行缓存。

c. max-age

指定从请求的时刻开始计算,此响应的缓存副本有效的最长时间,单位:秒。

max-age指定的是缓存的时间跨度,而非缓存失效的时间点,不会受到客户端与服务器时间误差的影响。

强制缓存策略下(Cache-control未指定no-cache和no-store)的缓存判断流程:

2)Etag和If-none-match

Etag是服务器为资源分配的字符串形式唯一性标识,作为响应首部信息返回给浏览器。

浏览器在Cache-control指定no-cache或者max-age和Expires均过期之后,将Etag值通过If-none-match作为请求首部信息发送给服务器。

服务器接收到请求之后,对比所请求资源的Etag值是否改变,如果未改变将返回304 Not Modified,并且根据既定的缓存策略分配新的Cache-con1xinx;如果资源发生了改变,则会返回最新的资源以及重新分配的Etag值。

整体流程如图:

如果强制浏览器使用协商缓存策略,需要将Cache-control首部信息设置为no-cache,这样便不会判断max-age和Expires过期时间,从而每次资源请求都会经过服务器对比。

3.5.2 覆盖更新与增量更新

覆盖更新与增量更新都是建立在启用浏览器强制缓存策略的前提下的。

增量更新是目前被业界广泛使用的前端静态资源更新策略,普遍的实现方案是通过为文件名添加hash指纹。

覆盖更新的缺陷较多且没有较好的解决方案,目前已逐渐被淘汰。

覆盖更新策略的实现方案是在引用资源的URL后添加请求参数,将hash指纹作为url参数值实现覆盖更新的方案有两个缺陷:

1)必须保证html文件与改动的静态文件同步更新,否则会出现资源不同步的情况;

2)不利于版本回滚。

增量更新策略完美解决了上述缺陷,将原本作为参数值的hash指纹作为资源文件名的一部分并且删除用于更新的url参数。

在静态资源使用增量更新策略的前提下,可以将静态资源先于动态html部署,此时静态资源没有引用入口,不会对线上环境产生影响;动态html部署后即可在第一时间访问已存的最新静态资源。这样便解决了覆盖更新部署同步性的问题。

增量更新修改了资源文件名,不会覆盖已存的旧版本文件,运维人员进行回滚操作时只需回滚html即可。这样不仅优化了版本控制,而且还可以支持多版本共存的需求。

3.5.3 按需加载与多模块架构场景下的增量更新

多模块架构指的是存在多个互不干扰的模块体系,这些模块体系可能存在于同一页面中,也可能存在于两个独立页面。

1)同步模块的修改对异步文件和主文件hash指纹的影响

同步模块的修改影响主模块的hash指纹,对异步文件无影响。

2)异步模块的修改对主模块的hash指纹产生的影响

异步模块的修改不仅仅影响其对应异步文件的hash指纹,主文件的hash指纹也必须同步修改,这样才能保证用户得到最新的异步文件。

3.6 资源定位

Web项目中的资源定位指的是存在引用关系的资源之间被引用方地址的改动都会被及时同步到引用方。具体到构建系统还有另外一层含义:以引用方为入口寻找被引用方并且进行构建。

3.6.1 常规的资源定位思维

HTML是Web站点的入口,其他所有类型的静态资源均需要直接或间接地被HTML文档引用才可以被加载。

浏览器先访问HTML文档,根据其引用静态资源的地址、先后顺序依次进行加载。也就是说,浏览器必须通过HTML文档才可以知道Web站点需要哪些静态资源。

同理,在构建阶段,HTML文档中引用了哪些文件以及这些文件具体的引用位置是作为资源定位和地址替换的唯一依据。

3.6.2 Webpack的逆向注入模式

Webpack将JS视为一切资源的入口,不论是直接还是间接,只要与entry配置的js文件存在引用关系的资源都会参与构建。

HTML在Webpack中与CSS一样属于“次等公民”,可以使用html-webpack-plugin编译HTML并且将其导出为独立的文件。

Webpack解决资源定位并不是按照上文所述的“正向”顺序,而是将项目构建输出的js和css文件“逆向”地注入到HTML文档中。

到此这篇前端工程化工具包括哪些(前端工程化工具包括哪些内容)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • 前端埋点怎么写(前端埋点和后端埋点的区别)2025-02-11 20:00:07
  • 前端埋点框架设计(前端埋点框架设计方案)2025-02-11 20:00:07
  • 前端工程化的理解面试题(什么是前端工程化.前端面试题)2025-02-11 20:00:07
  • 前端工程化解决方案(前端工程化的好处)2025-02-11 20:00:07
  • 前端工程化的意义(前端工程化的理解简书)2025-02-11 20:00:07
  • 前端埋点工具(前端埋点插件)2025-02-11 20:00:07
  • 前端工程化体系(前端工程化概念)2025-02-11 20:00:07
  • 前端模块化解决方案(前端模块化的好处)2025-02-11 20:00:07
  • 前端解决跨域请求(前端跨域请求头)2025-02-11 20:00:07
  • 前端跨域解决方案(前端跨域解决方案cors设置星号)2025-02-11 20:00:07
  • 全屏图片