项目上线一段时间后如果更新JS或CSS文件,而客户端已经对该文件缓存过了,那就有可能会无法及时更新而继续采用旧的JS或CSS文件,无法达到想要的效果。
处理类似情况最有效的解决方案就是修改其所有的链接,这样,请求就会从服务器下载最新的内容。但是要怎么改呢?
一:通过query的方式添加随机数。这样虽然可以保证每次都能获取到最新的静态资源,但即使没有更新也会去重新下载,缓存也就失去了意义,增加了服务器的负担。
二:通过query的方式添加时间戳或者版本号
<script type="text/javascript" src="index.js?t=20170325"></script>
<script type="text/javascript" src="index.js?v=1.0.0.0"></script>
这种解决方案很是直观,每次更新只需要更新相关的静态资源和页面,做到了局部更新,减轻了服务器负担,同时也使得浏览器缓存得到了有效利用。
但是,如果是访问量比较大的网站的话,还是会面临一些新的问题的。
通常,发布新版本也就是发布新的静态资源和页面的过程。比如:要发布一个index.aspx的页面,同时引入了index.js的资源。发布新版本就是要覆盖服务器上的这两个文件,不管你怎么操作,这两个文件在覆盖的过程中总会产生时间间隙的,对于访问量达的网站,在这个时间间隙内有可能是会出现新的用户访问的,这时,错误就发生了,新页面旧的静态资源或者旧页面新的静态资源。由于静态资源是覆盖发布,对于使用CDN缓存的网站来说还有可能面临CDN缓存攻击。
三:基于文件内容的hash版本冗余机制,也就是直接修改文件的URL,而不是在其后添加query
<script type="text/javascript" src="index_a5dae5b.js"></script>
其中”_a5dae5b”字符是根据index.js的文件内容进行hash运算得到的,只有文件内容发生变化了才会有更改。
由于不是同名覆盖,这样就完美的解决了发布的间隙问题,可以做到无缝连接;同时遇到问题回滚的时候只需要回滚页面就可以了。
但是要怎么来实现呢?
于是我问了下度娘(谷歌每次都得FQ,慢还麻烦,先问度娘,解决不了在出墙去),这次居然靠谱的找到了FIS,百度的一个开源的前端工程构建工具。
FIS的功能还是很强大的,而且文档很详细,而且还是中文…至于怎么安装和使用,http://fis.baidu.com/fis3/index.html这里你想要的都有。需要先安装node和npm。
我本地node的安装版本是v6.9.5,npm安装版本v3.10.10,FIS的安装版本是v3.4.32
由于是第一次接触FIS,所以先用一点简单的功能,添加MD5戳和压缩资源,配置文件如下:
fis.match('*.{js,css}', {
useHash: true
});
fis.match('*.js', {
// fis-optimizer-uglify-js 插件进行压缩,已内置
optimizer: fis.plugin('uglify-js')
});
fis.match('*.css', {
// fis-optimizer-clean-css 插件进行压缩,已内置
optimizer: fis.plugin('clean-css')
});
fis.match('*.png', {
// fis-optimizer-png-compressor 插件进行压缩,已内置
optimizer: fis.plugin('png-compressor')
});
release完了之后用visual studio发布报错:常量中有换行符。我发现凡是涉及到这个错误的有一个共同点就是都存在中文或者中文字符。于是我想到应该是编码的问题。于是我把文件编码格式改成了utf-8,再次编译顺利通过。
但是发布部署之后浏览发现所有的静态资源都没有正常加载,看了一下源代码,发现通过FIS release之后已经默认都改成了绝对路径。不行让它用绝对路径怎么办?
我去找了一下文档,发现FIS的插件中有个是可以让产出能够支持相对路径的插件:fis3-hook-relative。具体安装使用https://github.com/fex-team/fis3-hook-relative
修改刚才的配置文件,在原来的基础上启用该插件,完整的配置文件如下:
// 让所有文件,都使用相对路径。
fis.match('**', {
relative: true
})
//加 md5
fis.match('*.{js,css}', {
useHash: true
});
fis.match('*.js', {
// fis-optimizer-uglify-js 插件进行压缩,已内置
optimizer: fis.plugin('uglify-js')
});
fis.match('*.css', {
// fis-optimizer-clean-css 插件进行压缩,已内置
optimizer: fis.plugin('clean-css')
});
fis.match('*.png', {
// fis-optimizer-png-compressor 插件进行压缩,已内置
optimizer: fis.plugin('png-compressor')
});
release之后发布部署,一切恢复正常!!!这样既很好的解决了JS或者CSS缓存的问题!
因为添加MD5戳是根据文件内容生成的,所以完全不必担心手工替换时会漏掉的页面,一个命令就自动帮你解决了这些问题。
FIS还支持Glob语法扩展,更扩展了分组功能,进行文件匹配的时候真正使简单易容~吼吼