7月阅读周·前端架构:从入门到微前端 | 架构基础:设计构建流
背景
去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。
没有计划的阅读,收效甚微。
新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。
这个“玩法”虽然常见且板正,但是有效,已经坚持阅读六个月。
已读完书籍:《架构简洁之道》、《深入浅出的Node.js》、《你不知道的JavaScript(上卷)》、《你不知道的JavaScript(中卷)》、《你不知道的JavaScript(下卷)》、《数据结构与算法JavaScript描述》、《WebKit技术内幕》。
当前阅读周书籍:《前端架构:从入门到微前端》。
架构基础:设计构建流
构建系统是一个Web应用不可缺少的一部分,其核心用途是,帮助开发者从源代码开发开始,构建出最后可用的目标软件。开发人员还能通过构建系统中的构建工具添加更多实用的功能,如修改监测代码触发代码编译后自动地刷新浏览器,在构建系统时配置不同的环境参数,在本地运行的时候做反向代理,等等。通常,在一个前端应用中,构建系统需要做下面的一些事情:
- 依赖管理及安装。
- 优化开发环境。
- 代码质量检测。
- 编译及打包。
- 测试及部署。
依赖管理工具
在项目的源码管理中,依赖的管理是相当重要的一部分。它可以使代码在项目的各个开发机器、持续集成服务器上快速地搭建、运行、发布,而不需要确认依赖版本等额外的工作。早期没有依赖管理软件时,项目的依赖放在代码库中——每次更新依赖的时候,均需向项目的代码库提交一个新的版本,这导致项目的代码库越来越大,对新成员越来越不友好。在有了依赖管理之后,我们只要执行安装命令,如npm install,再执行运行服务就可以进行开发了。
1、不同的模块化方案
在继续讨论依赖管理之前,我们不得不再次提及AMD、CommonJS和UMD,它们是三种不同的JavaScript模块化方案。这些模块化方案,在一定程度上影响着项目的依赖管理。
AMD(Asynchronous Module Definition)即异步模块定义,其典型的表现形式是通过构建好的JavaScript库文件,直接在浏览器中引入依赖,典型的框架有jQuery。为了引用这些采用AMD方式的库,我们还需要使用诸如require.jsjs这样的AMD管理库来管理依赖。如果这些AMD库是在浏览器上通过script直接引入并运行的,那么它们就可以使用bower来进行管理。
CommonJS最初被用于在非浏览器端使用JavaScript来管理模块,比如使用Node.js来开发服务器应用。设计的目的是避免模块定义全局对象,即JavaScript的作用域问题。在CommonJS库里,每个文件就是一个模块。开始时,CommonJS在Node.js服务端运行,随着Browserify和webpack能将这些CommonJS编译为浏览器能运行的JavaScript,越来越多的前端框架直接使用CommonJS来管理模块。
随着AMD和CommonJS的流行,又产生了UMD(Universal Module Definition,通用模块定义),它是AMD和CommonJS的糅合,它会判断是否是Node.js的模块。
2、AMD方式:通过Bower进行管理
谈到AMD库的管理,一般会有两种方式,一种是直接下载对应的库,另一种是可以由后来的Bower进行管理。
在有了Bower之后,开发者只需要在bower.json文件中添加所需要的依赖,就可以由Bower自动下载这个依赖的相关内容——该库打包到bower的服务器上(Bower是一个包管理工具),它可以管理包含HTML、CSS、JavaScript、字体甚至图像文件的组件。Bower的工作原理是,从各个地方获取安装包,并搜索、查找、下载和保存正在寻找的内容。因此,Bower在过去的某段时间里非常流行。
3、CommonJS方式:通过NPM/Yarn管理
NPM(Node Package Manager, Node包管理器)是JavaScript世界的包管理工具,并且是Node.js平台的默认包管理工具。开发人员通过NPM可以安装、共享、分发代码,并管理项目依赖关系。此外,这些包会分发到NPM的官方网站npmjs.org上,以便对NPM包进行更好的管理。
除了NPM,还可以使用Yarn来管理依赖。Yarn是由Facebook推出的一款新的JavaScript包管理工具,其特色是Yarn会缓存它下载的每个包,因此不用重复下载就可以加快安装速度。随着Yarn提出缓存包的功能,NPM也提供了相似的功能。
目前主流的前端应用框架(React、Angular、Vue)支持并采用的方式主要以编译构建为主,大都采用NPM+CommonJS的形式来管理依赖。
软件包源管理
在确认了安装的工具之后,我们需要考虑软件包源的问题。NPM使用package.json来管理依赖,在这个文件中定义依赖的内容和版本。软件包源有以下几种方式:
- 公有/私有软件包源服务器。
- 基于源码版本管理服务器,比如直接使用Git服务器来管理和分布库的版本。
- 本地的软件包,使用相对路径导入本地仓库。
这几种方式可以单独使用,也可以结合起来使用。公有/私有软件包源服务器对于直接使用源服务器来说,有以下几种方式:
- npmjs.org提供的官方源。它可以提供最新的软件包,但是国内开发者使用的时候会受到影响。
- 淘宝的cnpm源。它可以为国内的开发者提供更快速的下载服务。
- 搭建私有的NPM服务器,提供更为安全快速的Node.js环境。
对于小型组织来说,软件包通常来源于NPM包管理中心。而在大中型企业中,对于软件包的管理则会更谨慎一些。除了放置那些不适合公开的库,它还可以保证应用的构建不受外部的干扰——比如外部软件包中心宕机。对于那些因为安全原因隔离内部/外部网络的公司来说,则更需要这样的软件包仓库。
前端代码的打包
在主流的前端框架里,编译及打包的工作都已经交给对应框架的CLI(Command-Line Interface,命令行界面)来完成了,例如Angular的CLI、Vue的CLI,以及Facebook推出的Create-React-App。在这些工具里,只有Angular可以真正地实现开箱即用,这和Anguar本身大而全的设计有关。因此,当我们选择使用Vue、React等其他框架时,或多或少地需要进行一些定制,这就要求我们对应用本身的打包有一定了解。
代码打包的最后一步就是,一一将代码“拼接”到一起,压缩并混淆代码,最后构建出目标代码文件。期间,还会进行可选的摇树优化(Tree Shaking,顾名思义就是去掉不需要用到的代码),其主要依赖于ES6模板及其带来的静态分析。这个目标文件是按我们的需要而产生的。
设计构建流
构建流的设计是逐步演进的,很难在项目初始时便设计出完整的构建流。对于复杂的应用来说,在开发应用的过程中会不断地完善。对于简单的应用来说,事先设计好的流程可能用不上。
构建流通常来源于:
- 过去的开发经验。
- 前端框架提供的命令。
- 应用脚手架提供的功能。
不管哪种形式提供的构建流,多数时候都需要经过一定的改造才能满足我们的需求。
持续交付问题
如果应用构建成功,那么就可以着手部署应用了。大部分前端应用的部署并不复杂,只需要将最后构建生成的目标文件,安装或者复制到指定的线上目录即可——如HTTP服务器指向的固定路径。由于其部署简单,有一定Linux使用经验的开发者都可以独立完成部署。在笔者经历的多数项目里,尽管身为前端的技术主管,但都不需要半夜去上线,而是交由后端开发人员来完成。
部署方式
对于前端应用来说,其部署方式和后端的区别不大,从方式上可以分为如下三种。
- 持续部署。构建完成即部署,常见于测试环境。
- 自动化部署。在持续部署的基础上稍微弱化,即需要人为的介入才能自动化部署。
- 手动部署。即全程需要人为操作的部署流程。
不论是自动化部署还是手动部署,都需要一个确定的发布策略——不论是敏捷模式还是瀑布模式。敏捷模式的上线发布计划是一个分布迭代(通常两周一次),随后不断地发布;而瀑布模式则是一次上线就完成大部分主要功能。
持续不断地发布应用的优点在于,让团队成员适应快速变化和发布的节奏,并有能力快速解决应用发布过程中出现的问题,而不是在一次上线之后匆忙地应对各种可能发生的情况。对于大型组织下的项目而言,受限于组织内部的上线策略,并不是所有的敏捷项目都可以按迭代上线,但是我们都可以在内部发布,并在过程中持续地改进发布流程。
设计持续集成
前端项目持续集成的主要内容如下:
- 对应用进行构建。
- 进行应用的测试,利用代码来完成测试有助于减少bug。
- 部署应用到对应的环境,以提供一个联调和测试环境。
我们需要做的事情有:
- 找到相应的工具。
- 进行相应的配置。
- 运行本章中完成的构建脚本。
- 编写部署脚本。
总结
阅读本篇文章可以有以下收获
- 了解通用的前端应用构建流程,以及在其背后的依赖管理、包管理和发布机制。
- 了解前端应用的构建流设计。常用的构建工具:Gulp、Grunt及webpack,同时还有其背后的一些基本思想——基于配置的构建、基于代码和流的构建方式。并分别使用这两种思想,来完成一个前端应用的构建流设计。通过这些实例,开发者可以更容易地探索现有应用的构建流程。
- 结合配置构建和持续集成,了解前端应用的持续部署进。
作者介绍
非职业「传道授业解惑」的开发者叶一一。
《趣学前端》、《CSS畅想》等系列作者。华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞👍 | 收藏⭐️ | 留言📝。
- 点赞
- 收藏
- 关注作者
评论(0)