发布
发布分为覆盖式发布和增量式发布。
覆盖式发布
覆盖式发布指前端将构建好的资源直接上传到目标服务器,覆盖旧的资源。比如使用FTP工具进行服务器单点上传,或者使用shell脚本进行批量上传。早期的页面应用并不复杂,覆盖式发布不仅简单,还能有效节省硬盘空间。在很长一段时间内,覆盖式发布都是前端的主要发布手段。
随着页面应用的复杂度和访问量上升,覆盖式发布的问题逐渐暴露。假设有这样一个简单的前端页面,它由index.html和style.css两个文件组成。
index.html文件的内容如下。
<link rel="stylesheet" href="style.css">
<div class ="foo">foo</div>
style.css内容如下:
.foo{
color:red;
}
开发人员需要进行功能改动,对两个文件的内容进行了修改。
<link rel="stylesheet" href="style.css">
<div class="bar">bar</div>
.bar{
color:red;
}
按照覆盖式发布的部署流程,需要将修改后的两个文件上传到服务器,覆盖旧的文件。在上传的过程中,两个文件不可能同时被覆盖,必定存在着先后顺序,包括两种情况。
index.html先被覆盖,style.css后被覆盖。在两个资源覆盖期间,如果有用户访问了页面,那么他访问的将是新的index.html和旧的style.css,结果就是页面上的bar没有样式修饰。
style.css先被覆盖,index.html后被覆盖。在两个资源覆盖期间,如果有用户访问了页面,那么他访问的将是新的style.css和旧的index.html,结果就是页面上的foo没有样式修饰。
以上仅列举了在文件数量和类型比较简单的情况下,使用覆盖式发布可能导致的问题。随着页面依赖的文件数量增加,不仅部署的时间会更长,部署时文件覆盖的先后顺序也更加多变。如果在页面依赖的某个.js文件里,某部分代码依赖了DOM结构,那么.html文件中的变更可能导致页面某个功能不可用,这是比样式错乱更为严重的问题。以上情况在页面文件依赖越复杂,页面访问量越大时越容易出现。
为了避免出现以上问题,开发人员开始选择在页面访问量处于低谷时部署系统,因为此时出错的概率比较小。访问量低谷期通常处于深夜,这将增加部署人员的负担,而且依然有可能出现问题。
覆盖式发布存在一个没有办法避免的严重问题:当部署的代码出现问题时,服务器上的资源不能直接回滚到上一次的状态。开发人员必须在本地将代码回退到之前的状态,然后重新进行构建打包,重新上传资源才能实现回滚。整个回滚期间会耗费大量的时间和精力,并且在回滚完成之前,生产环境的故障依然存在。
非覆盖式发布
非覆盖式发布指前端在将构建好的资源直接上传到目标服务器时,只做增量更新,不会覆盖旧的资源。为了实现这一目标,可以在页面依赖的文件资源名称上添加版本后缀,这样在上传时就不会相互覆盖。同样以上一节的两个文件为例,为文件名称添加版本后缀,改造结果如下。
<link rel="stylesheet" href="style_v1.css">
<div class="foo">foo</div>
//style_v1.css
.foo{
color:red;
}
如果需要进行功能改动,那么修改后的结果如下。
<link rel ="stylesheet" href="style_v2.css">
<div class ="bar">bar</div>
//style_v2.css
.bar{
color:red;
}
此时先将style_v2.css文件上传到服务器,然后将index.html文件上传到服务器,更新入口页面。当style_v2.css文件被上传到服务器时,旧的index.html文件依赖的依然是style_v1.css文件,并不依赖style_v2.css文件;当新的index.html文件被上传到服务器时,style_v2.css文件已经被上传到服务器,不会出现资源无法访问的情况。因此,非覆盖式发布不会出现新旧文件交替依赖的情况,由此可以有效避免资源上传间隔导致的样式错乱问题。
当文件的数量变多、依赖关系变复杂后,手动添加版本后缀的方式不再可靠。面对这种情况,可以使用文件的哈希值作为后缀。当一个文件内容发生变化后,对应的哈希值也会发生变化,以确保文件名称的唯一性。许多构建打包工具都支持文件名称添加哈希值后缀的功能,例如,webpack、Rollup等。
非覆盖式发布有效解决了覆盖式发布的问题,在资源部署期间不会出现页面问题。同时,由于非覆盖式发布使用文件的哈希值作为名称后缀,避免了资源相互覆盖,当线上代码出现问题时可以快速进行回滚。它的缺点是会在服务器上积累大量的无用资源,该问题只需要定时清理即可解决。当index.html作为入口页时,不能添加哈希值作为文件后缀,回滚机制并不完善。