Gulp为网页增加静态资源指纹,后台无虑开启强缓存

Gulp为网页增加静态资源指纹,后台无虑开启强缓存

Gulp为网页增加静态资源指纹,后台无虑开启强缓存!

gulp

tips: 本文主要介绍了利用Gulp为网页增加静态资源指纹,以下方法也在日常生产中使用,由于网站服务有时候波动访问不了,建议先收藏到Github,仓库地址欢迎给个(star):

『gulp-revfile』 仓库地址: https://github.com/WeideMo/gulp-revfile

在开发历史上,有两个很大的难题,一是“命名”,二是处理缓存,鉴于互联网的飞速发展,缓存的使用率愈发增加,但是在缓存使用后,如何在合适(更新)的时候清除缓存,或者说通过何种方式解决缓存,正是此文书写的目的。

使用场景

在很长一段历史中,Web应用的开发需要不停的维护资源和资源的版本,开发者认为通过版本号可以有效解决Web应用中的缓存和清除缓存的问题,笔者很认同这个方法,然而在过去多年的时间中,人们通过各种以下各种方式进行缓存和更新缓存:

前端缓存

前端缓存,默认情况下其实利用到的是浏览器下的缓存机制,对生命周期内的静态资源进行缓存,通过访问浏览器对文件的缓存替代直接发起新的请求,通过减少请求开销(主要包括了创建HTTP请求,DNS查询,还有后台服务响应TTFB等),可有效的减少静态资源请求的网络开销;

而浏览器缓存的清除往往依赖于用户对浏览器的缓存的疯狂的刷新(谁说不是呢^_^),因此聪明的前端开发者通过使用静态资源的请求URL改变可以有效刷新缓存,从而达到了更新缓存的效果,主要方式有下:

更改文件名

通过更改静态资源请求链接中的资源名,如原来的 index.css → index_v1.css 可以通过新的资源名称发起新的请求,然而这种方式会有弊端,就是每次都要更新1个新的文件资源,哪怕通过脚本生产,文件的积累的和定期清理也是额外的开销;

queryString方式

就是现在开发中常用的通过请求参数的方式,进行传入版本参数进行更新缓存,如原来的是 index.css?v=1.0 → index.css?v=1.1 通过传入的参数的不同,浏览器会以新的HTTP请求方式请求新的资源,从而达到更新缓存的效果。虽然queryString的方式已经很大程度优化了文件生成的问题,但是随着开发周期推进,和资源数增加,那么维护起来还是十分的麻烦。

后端缓存

说到后端缓存,目前主要是通过反向代理服务器如Nginx或者 tengine等服务,通过开启后端缓存,把客户端请求的静态资源缓存到代理服务中,后续只要静态资源请求的时候,通过比对服务器中的缓存可以达到快速响应的能力。虽然后端缓存的能力十分强大,但是Ng的强缓存有时候会让客户端的缓存十分顽固,用户那边久久不能更新。

因此笔者为了解决日常生产中的缓存问题,通过笔者开发的 gulp-revfile 组件,方便快捷,自动的完成了清除缓存和版本维护的工作流程。

gulp-revfile

A web pages Demo works for avoiding cache by appending file hash in file request string
index.cssindex.css?v=ffcf8558f4

这是笔者在GitHub上对gulp-revfile的一个功能定义,做到就是通过读文件,生成文件指纹,最后自动编译到生产页面中,达到以下效果:

Effect(效果)

Source page

开发版页面效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--srcPages/html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>gulp-revDemo</title>
<link rel="stylesheet" href="../assets/css/index.css">
</head>
<body>
<div class="title">Easily make static files hash versions with [gulp-revm & gulp-revm-collector]:</div>
<div class="subTitle">Also works for javascript,css,images and so on...</div>
<images class="img" src="../assets/images/demo.jpg"></images>
</body>
<script src="../assets/images/js/jquery-1.10.2.min.js"></script>
<script src="../assets/images/js/testJs_1.js"></script>
<script src="../assets/images/js/testJs_2.js"></script>
</html>

Dest page

生产版页面效果(注意版本号):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!--srcPages/html-->
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>gulp-revDemo</title>
<link rel="stylesheet" href="../assets/css/index.css?v=ffcf8558f4">
</head>
<body>
<div class="title">Easily make static files hash versions with [gulp-revm & gulp-revm-collector]:</div>
<div class="subTitle">Also works for javascript,css,images and so on...</div>
<images class="img" src="../assets/images/demo.jpg?v=31b2c3b2c1"></images>
</body>
<script src="../assets/images/js/jquery-1.10.2.min.js?v=25db94fef9"></script>
<script src="../assets/images/js/testJs_1.js?v=d4c14c7af6"></script>
<script src="../assets/images/js/testJs_2.js?v=2ae0f37aea"></script>
</html>

通过两份代码对比,可以知道后者通过了queryString的方式增加了文件指纹,更让人惊喜的是,这个实现已经完全构建好在gulp流中,即各位开发者开箱可用了!现在允许我通过以下流程,一步步的去掌握gulp-revfile的迷人能力:

Install(安装)

  • gulp-revfile 仓库地址 - A web pages Demo works for avoiding cache by appending file hash in file request string index.cssindex.css?v=ffcf8558f4

clone or download this repository:克隆或者下载gulp-revfile仓库

1
$ npm install -g gulp
1
$ npm install

API(调用方法)

Fetch source file:获取源文件

1
gulp.src('assets_dev/js/**/*.js')

rev() Read file contents ready for generation:读取文件准备生成

1
2
gulp.src('assets_dev/images/**/*.jpg')
.pipe(rev());

rev.manifest() Generate file hash version:生成文件hash版本号

1
2
3
gulp.src('assets_dev/images/**/*.jpg')
.pipe(rev())
.pipe(rev.manifest());

revCollector() Writes the static resource version number to the target HTML file:写入目标网页文件

1
2
3
4
gulp.src([ PATH_REV_JSON, PATH_SRC_HTML ])
.pipe(revCollector({
replaceReved:true
}));

Usage(用法)

Dependency prefix:依赖前置

1
2
3
4
5
6
//gulpfile.js
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var rev = require('gulp-revm');
var revCollector = require('gulp-revm-collector');
var cssmin = require('gulp-minify-css');

Constant definition:定义常量路径

1
2
3
4
//gulpfile.js
var PATH_SRC_HTML = 'srcPages/**/*.html';
var PATH_DES_HTML = 'destPages/';
var PATH_REV_JSON = 'rev/**/*.json';

Files watch:文件监控触发任务

1
2
3
4
5
6
//gulpfile.js
gulp.task('watchChange',function() {
console.log("watcher has started");
gulp.watch('assets_dev/js/**/*.js', ['rev_js']);
gulp.watch('srcPages/**/*.html',['rev_html']);
});

Gulp task define:gulp处理任务定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//gulpfile.js
/*----------javascript MD5 version process----------*/
gulp.task('jsmin', function() {
return gulp.src('assets_dev/js/**/*.js')
.pipe(uglify())
.pipe(rev())
.pipe(gulp.dest('assets/js'))
.pipe(rev.manifest())
.pipe(gulp.dest('rev/js'));
});
/*----------reversion Javascript deps on task[jsmin]----------*/
gulp.task('rev_js',['jsmin'],function(cb){
gulp.src([ PATH_REV_JSON, PATH_SRC_HTML ])
.pipe(revCollector({
replaceReved:true
}))
.pipe(gulp.dest( PATH_DES_HTML ));
cb();
});
/*----------reversion html pages----------*/
gulp.task('rev_html',function(cb){
gulp.src([ PATH_REV_JSON, PATH_SRC_HTML ])
.pipe(revCollector({
replaceReved:true
}))
.pipe(gulp.dest( PATH_DES_HTML ));
cb();
});

Start gulp task(default:watchChange):启动默认监听任务:watchChange

1
$ gulp watchChange

Edit any file that under watch: javascript,css sheet even and images:编辑任何监控任务下的文件

The corresponding file automatically generates the version number based on the hash value of the file, which is generated in the rev directory.

对应的文件会根据文件的哈希值自动生成版本号生成在rev目录下。

At the same time, gulp will according to rev under the hash version number, and read the srcPages file under the HTML page, and the version number is added to the destPages file.

同时,gulp会根据rev下的hash版本号并读取srcPages文件下的html页面并将版本号加入到destPages文件下。

Effect(效果)

见前文叙述 _

More Tips(更多)

Relatived gulp plugin:相关插件

  • gulp-revm - Static asset revisioning by appending content hash to filenames: index.css => index.css?d41d8cd98f.
  • gulp-revm-collector - Static asset revision data collector from manifests, generated from different streams, and replace their links in html template.
  • gulp-css-spriterm - Gulp-css-spriterm is based on the revised version of gulp-css-spriter, mainly to do clear cache processing for naming Sprite map.

Works for multi types source file:支持多种源文件类型

By looking at demo, you can see that you can get hash values for different files by listening to different types of files, including JS scripts, CSS styles and picture files, and so on, as well as other files.

通过查看demo可以知道,通过监听不同类型的文件可以获取不同文件的hash值,包括了js脚本,css样式和图片文件等,其他文件同理可以

Works for multi types target page-file:支持多种源文件类型

Gulp-revfile can write hash versions to different types of web pages, such as HTML, shtml, PHP, JSP, and so on

gulp-revfile可以将hash版本写入不同类型的网页文件,如html,shtml,php,jsp等

Automatic generation: 编辑自动生成

After startup watch Task, the file version number will be automatically completed when the file is modified.

启动监控后,文件版本号会在修改文件的时候自动完成

Summary(总结)

gulp-revfile是基于为页面增加文件指纹版本去除缓存的一个gulp流程工具,笔者已经封装好了一个简单的demo,有疑问或者不熟悉的同学,可以到 gulp-revfile 仓库地址进行clone下载,如果喜欢的或者对你们的工作有帮助,由衷恳请各位小伙伴对项目基于一个star ★, 谢谢阅读!