详解前端自动化工具gulp自动添加版本号


Posted in Javascript onDecember 20, 2016

之前,我介绍了学习安装并配置前端自动化工具Gulp,觉得gulp确实比grunt的配置简单很多,于是我决定再深入学习一下gulp,就去网上查了资料,发现gulp还可以自动添加版本号,这个功能就为我平时在更新css或js时老是在客户端存在缓存导致更新后的效果无法实时展现的苦恼。所以就赶紧去试了一下,果真可以,很高兴啊,真是为项目开发,为效果的快速展现提供了很多的便利。

实现原理:

1、修改js和css文件;

2、通过对js,css文件内容进行hash运算,生成一个文件的唯一hash字符串(如果文件修改则hash号会发生变化);

3、替换html中的js,css文件名,生成一个带版本号的文件名。

现在网上的方案都是生成一个新的dist目录,里面包含了要发布的html、js、css等文件。但是在实际的公司的项目中,会有情况不能生成新的HTML进行发布,需要在原来的HTML文件上进行js 、css版本的替换. 这里分享下我在实际项目中通过改动插件然后在原目录结构下进行版本的控制方案。(在这里,我有点不太明白原作者的意思,因为你既然修改了js或css,那么html中引入这些文件的版本号必然会发生变化,也就是html也跟着变化了,如果你不对新的html进行发布,那线上的html中的版本号还是老的版本号,就没有起到更新缓存的作用,那我们辛辛苦苦的配置gulp来添加这个版本号干嘛?)

原html文件代码

<link rel="stylesheet" href="../css/default.css">
<script src="../js/app.js"></script>

预期效果:在原目录结构下html文件代码

<link rel="stylesheet" href="../css/default.css?v=5a636d79c4">
<script src="../js/app.js?v=3a0d844594"></script>
background:url("../images/none.png?v=8f204d4")

实现方法:

1、安装gulp和gulp插件

npm install --save-dev gulp
npm install --save-dev gulp-rev
npm install --save-dev gulp-rev-collector
npm install --save-dev gulp-asset-rev
npm install --save-dev run-sequence

2、编写gulpfile.js

//引入gulp和gulp插件
var gulp = require('gulp'),
  assetRev = require('gulp-asset-rev'),
  runSequence = require('run-sequence'),
  rev = require('gulp-rev'),
  revCollector = require('gulp-rev-collector');

//定义css、js源文件路径
var cssSrc = 'css/*.css',
  jsSrc = 'js/*.js';

//为css中引入的图片/字体等添加hash编码
gulp.task('assetRev', function(){
  return gulp.src(cssSrc)  //该任务针对的文件
   .pipe(assetRev()) //该任务调用的模块
   .pipe(gulp.dest('src/css')); //编译后的路径
});

//CSS生成文件hash编码并生成 rev-manifest.json文件名对照映射
gulp.task('revCss', function(){
  return gulp.src(cssSrc)
    .pipe(rev())
    .pipe(rev.manifest())
    .pipe(gulp.dest('rev/css'));
});


//js生成文件hash编码并生成 rev-manifest.json文件名对照映射
gulp.task('revJs', function(){
  return gulp.src(jsSrc)
    .pipe(rev())
    .pipe(rev.manifest())
    .pipe(gulp.dest('rev/js'));
});


//Html替换css、js文件版本
gulp.task('revHtml', function () {
  return gulp.src(['rev/**/*.json', 'View/*.html'])
    .pipe(revCollector())
    .pipe(gulp.dest('View'));
});


//开发构建
gulp.task('default', function (done) {
  condition = false;
  runSequence(    //需要说明的是,用gulp.run也可以实现以上所有任务的执行,只是gulp.run是最大限度的并行执行这些任务,而在添加版本号时需要串行执行(顺序执行)这些任务,故使用了runSequence.
    ['assetRev'],
    ['revCss'],
    ['revJs'],
    ['revHtml'],
    done);
});

执行gulp命令后的效果

//rev目录下生成了manifest.json对应文件
{
 "default.css": "default-803a7fe4ae.css"
}


<link rel="stylesheet" href="../css/default-803a7fe4ae.css">
<script src="../js/app-3a0d844594.js"></script>

很显然这不是我们需要的效果

3、更改gulp-rev和gulp-rev-collector

打开node_modules\gulp-rev\index.js

第144行 manifest[originalFile] = revisionedFile;

更新为: manifest[originalFile] = originalFile + '?v=' + file.revHash;

打开nodemodules\gulp-rev\nodemodules\rev-path\index.js

10行 return filename + '-' + hash + ext;

更新为: return filename + ext;

打开node_modules\gulp-rev-collector\index.js

31行 if ( !_.isString(json[key]) || path.basename(json[key]).replace(new RegExp( opts.revSuffix ), '' ) !==  path.basename(key) ) {

更新为: if ( !_.isString(json[key]) || path.basename(json[key]).split('?')[0] !== path.basename(key) ) {

打开node_modules\gulp-assets-rev\index.js

78行 var verStr = (options.verConnecter || "-") + md5;

更新为:var verStr = (options.verConnecter || "") + md5;

80行 src = src.replace(verStr, '').replace(/(\.[^\.]+)$/, verStr + "$1");

更新为:src=src+"?v="+verStr;

再执行gulp命令,得到的结果如下(效果正确):

<link rel="stylesheet" href="../css/default.css?v=803a7fe4ae">
<script src="../js/app.js?v=3a0d844594"></script>
background:url("../images/none.png?v=8f204d4")

但是假如我们更改了css和js后,再执行gulp命令,得到的结果会如下:

<link rel="stylesheet" href="../css/default.css?v=33379df310?v=803a7fe4ae">
<script src="../js/app.js?v=3a0d844594?v=3a0d844594"></script>

有没有发现,会在版本号后面再添加一个版本号,因为gulp只替换了原来文件名,这样又不符合预期效果了,所以我们想到,还需要修改插件的替换正则表达式。

4、继续更改gulp-rev-collector

打开node_modules\gulp-rev-collector\index.js

第107行 regexp: new RegExp( '([\/\\\\\'"])' + pattern, 'g' ),

更新为: regexp: new RegExp( '([\/\\\\\'"])' + pattern+'(\\?v=\\w{10})?', 'g' ),

现在你不管执行多少遍gulp命令,得到的html效果都是

<link rel="stylesheet" href="../css/default.css?v=5a636d79c4">
<script src="../js/app.js?v=3a0d844594"></script>

以下是本人自己写的一个既可以编译less,又可以压缩、重命名css和js,同时可以压缩html并自动添加版本号的gulp.js配置文件,当然也是参考了原作者的方法:

//引入gulp和gulp插件
var gulp = require('gulp'),
  less = require('gulp-less'),
  assetRev = require('gulp-asset-rev'),
  minifyCss = require('gulp-minify-css'),
  uglify = require('gulp-uglify'),
  htmlmin = require('gulp-htmlmin'),
  rename = require('gulp-rename'),
  imagemin = require('gulp-imagemin'),
  runSequence = require('run-sequence'),
  rev = require('gulp-rev'),
  revCollector = require('gulp-rev-collector');

//定义css、js源文件路径
var cssSrc = 'css/*.css',
  cssMinSrc = 'dist/css/*.css',
  jsSrc = 'js/*.js',
  jsMinSrc = 'dist/js/*.js',
  lessSrc = 'less/*.less',
  imgMinSrc = 'dist/images/*.{png,jpg,gif,ico}',
  htmlSrc = '*.html';

//编译less 定义一个less任务(自定义任务名称)
gulp.task('less', function(){
  return gulp.src(lessSrc)  //该任务针对的文件
   .pipe(less()) //该任务调用的模块
   .pipe(gulp.dest('css'));//编译后的路径
});

//为css中引入的图片/字体等添加hash编码
gulp.task('assetRev', function(){
  return gulp.src(cssSrc)  //该任务针对的文件
   .pipe(assetRev()) //该任务调用的模块
   .pipe(gulp.dest('src')); //编译后的路径
});

//压缩css
gulp.task('cssMin', function() {
  return gulp.src(cssSrc)   //压缩的文件
    .pipe(rename({suffix: '.min'}))  
    .pipe(minifyCss()) //执行压缩
    .pipe(gulp.dest('dist/css'));  //输出文件夹
});

//CSS生成文件hash编码并生成 rev-manifest.json文件名对照映射
gulp.task('revCss', function(){
  return gulp.src(cssMinSrc)
    .pipe(rev()) //文件名加MD5后缀
    .pipe(rev.manifest())  //必须有这个方法 生成一个rev-manifest.json
    .pipe(gulp.dest('dist/css'));  //将rev-manifest.json 保存到 dist/css 目录内
});

//压缩js
gulp.task('uglify',function(){
  return gulp.src(jsSrc)
   .pipe(rename({suffix: '.min'}))
   .pipe(uglify())
   .pipe(gulp.dest('dist/js'));
});

//js生成文件hash编码并生成 rev-manifest.json文件名对照映射
gulp.task('revJs', function(){
  return gulp.src(jsMinSrc)
    .pipe(rev())
    .pipe(rev.manifest())
    .pipe(gulp.dest('dist/js'));
});

//压缩html
gulp.task('htmlMin',function(){
  var options = {
    collapseWhitespace:true,  //从字面意思应该可以看出来,清除空格,压缩html,这一条比较重要,作用比较大,引起的改变压缩量也特别大。
    collapseBooleanAttributes:true,  //省略布尔属性的值,比如:<input checked="checked"/>,那么设置这个属性后,就会变成 <input checked/>。
    removeComments:true,  //清除html中注释的部分,我们应该减少html页面中的注释。
    removeEmptyAttributes:true,  //清除所有的空属性。
    removeScriptTypeAttributes:true,  //清除所有script标签中的type="text/javascript"属性。
    removeStyleLinkTypeAttributes:true,  //清楚所有Link标签上的type属性。
    minifyJS:true,  //压缩html中的javascript代码。
    minifyCSS:true  //压缩html中的css代码。
  };
  return gulp.src(htmlSrc)
   .pipe(htmlmin(options))
   .pipe(gulp.dest('dist/html'));
});

//Html替换css、js文件版本
gulp.task('revHtml', function () {
  return gulp.src(['dist/**/*.json', 'dist/html/*.html'])
    .pipe(revCollector())
    .pipe(gulp.dest('dist/html'));
});

//压缩image
gulp.task('imageMin', function () {
  gulp.src('images/*.{png,jpg,gif,ico}')
    .pipe(imagemin())
    .pipe(gulp.dest('dist/images'));
});

gulp.task('revImage', function(){
  return gulp.src(imgMinSrc)
    .pipe(rev())
    .pipe(rev.manifest())  //必须有这个方法
    .pipe(gulp.dest('dist/images'));
});

gulp.task('default', function (done) {
  //condition = false;
  runSequence(  //此处不能用gulp.run这个最大限度并行(异步)执行的方法,要用到runSequence这个串行方法(顺序执行)才可以在运行gulp后顺序执行这些任务并在html中加入版本号
    'less',
    'assetRev',
    'cssMin',
    'revCss',
    'uglify',
    'revJs',
    'imageMin',
    'revImage',
    'htmlMin', 
    'revHtml',    
    done);
});

目前,不知为何必须要运行两次gulp才可以给html中引入的图片添加版本号,所以还在摸索中,也请大神给指点指点,谢谢!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Bookmarklet实现启动jQuery(模仿 云输入法)
Sep 15 Javascript
js 左右悬浮对联广告代码示例
Dec 12 Javascript
javascript将异步校验表单改写为同步表单
Jan 27 Javascript
jquery+ajax请求且带返回值的代码
Aug 12 Javascript
js代码实现无缝滚动(文字和图片)
Aug 20 Javascript
vue.js数据绑定的方法(单向、双向和一次性绑定)
Jul 13 Javascript
Bootstrap Table 删除和批量删除
Sep 22 Javascript
bootstrap fileinput插件实现预览上传照片功能
Jan 23 Javascript
Electron autoUpdater实现Windows安装包自动更新的方法
Dec 24 Javascript
关于vue表单提交防双/多击的例子
Oct 31 Javascript
微信jssdk踩坑之签名错误invalid signature
May 19 Javascript
详解CocosCreator项目结构机制
Apr 14 Javascript
详解Vue.js动态绑定class
Dec 20 #Javascript
浅谈Angular的$q, defer, promise
Dec 20 #Javascript
BootStrapTable服务器分页实例解析
Dec 20 #Javascript
bootstrap实现每隔5秒自动轮播效果
Dec 20 #Javascript
bootstrap多种样式进度条展示
Dec 20 #Javascript
JS封装通过className获取元素的函数示例
Dec 20 #Javascript
常用JS图片滚动(无缝、平滑、上下左右滚动)代码大全(推荐)
Dec 20 #Javascript
You might like
PHP中Session的概念
2006/10/09 PHP
js arguments对象应用介绍
2012/11/28 Javascript
登陆成功后自动计算秒数执行跳转
2014/01/23 Javascript
js 实现浏览历史记录示例
2014/04/20 Javascript
nodejs中实现路由功能
2014/12/29 NodeJs
JavaScript版的TwoQueues缓存模型
2014/12/29 Javascript
javascript制作的cookie封装及使用指南
2015/01/02 Javascript
详解jQuery中的empty、remove和detach
2016/04/11 Javascript
JS实现禁止用户使用Ctrl+鼠标滚轮缩放网页的方法
2017/04/28 Javascript
jQuery实现 RadioButton做必选校验功能
2017/06/15 jQuery
基于express中路由规则及获取请求参数的方法
2018/03/12 Javascript
Vue验证码60秒倒计时功能简单实例代码
2018/06/22 Javascript
浅析Vue实例以及生命周期
2018/08/14 Javascript
Bootstrap 按钮样式与使用代码详解
2018/12/09 Javascript
微信小程序与后台PHP交互的方法实例分析
2018/12/10 Javascript
node.js的Express服务器基本使用教程
2019/01/09 Javascript
JS中的算法与数据结构之栈(Stack)实例详解
2019/08/20 Javascript
[58:21]DOTA2亚洲邀请赛 4.3 突围赛 Liquid vs VGJ.T 第二场
2018/04/04 DOTA
50行代码实现贪吃蛇(具体思路及代码)
2013/04/27 Python
python解决Fedora解压zip时中文乱码的方法
2016/09/18 Python
python 实现tar文件压缩解压的实例详解
2017/08/20 Python
分析经典Python开发工程师面试题
2019/04/08 Python
基于jupyter代码无法在pycharm中运行的解决方法
2020/04/21 Python
Python selenium 加载并保存QQ群成员,去除其群主、管理员信息的示例代码
2020/05/28 Python
matlab、python中矩阵的互相导入导出方式
2020/06/01 Python
Python连接mysql方法及常用参数
2020/09/01 Python
Numpy中np.random.rand()和np.random.randn() 用法和区别详解
2020/10/23 Python
python3代码输出嵌套式对象实例详解
2020/12/03 Python
canvas学习和滤镜实现代码
2018/08/22 HTML / CSS
挪威手表购物网站:Klokker
2016/09/19 全球购物
DC Shoes荷兰官方网站:美国极限运动品牌
2019/10/22 全球购物
竞聘副主任科员演讲稿
2014/01/11 职场文书
2014社区三八妇女节活动方案
2014/03/30 职场文书
竞争上岗演讲稿范文
2014/05/12 职场文书
放飞梦想演讲稿200字
2014/08/26 职场文书
画错魏国疆域啦!《派对咖孔明》动画因作画失误于官网致歉
2022/04/07 日漫