前端自动化工具Gulp

之前,我介绍了学习安装并配置前端自动化工具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文件代码

预期效果:在原目录结构下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>


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

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

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

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

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

?


2

<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.js文件

var gulp = require('guip')
    , del = require('del')
    , browserSync = require('browser-sync')
    , uglify = require('gulp-uglify')
    , csso = require('gulp-csso') //css压缩
    , concat = require('gulp-concat') //文件合并
    , clean = require('gulp-clean')//清空文件夹
    , imagemin = require('gulp-imagemin') //
    , rename = require('gulp-rename') //文件重命名
    , rev = require('gulp-rev') //更改版本名
    , revCollector = require('gulp-rev-collector')//gulp-rev的插件,用于HTML模板更改引用路径
    , gulpsync = require('gulp-sync')(gulp); //异步处理

// 官网教程--------------

//删除文件
gulp.task('clean:mobile', function (cb) {
    del([
        '!dist/no/*',//取反模式
        'dist/*',
    ], cb)
});

// 监视文件改动并重新载入
gulp.task('serve', function () {
    browserSync({
        server: {
            baseDir: 'app'
        }
    });

    gulp.watch(['*.html', 'styles/**/*.css', 'scripts/**/*.js'],
        {cwd: 'app'}, browserSync.reload);//reload 也可以是其他的自定义任务
});

// 监视 Sass 文件的改动,如果发生变更,运行 'sass' 任务,并且重载文件
gulp.task('serve', ['sass'], function () {
    browserSync({
        server: {
            baseDir: 'app'
        }
    });

    gulp.watch('app/scss/*.scss', ['sass']);
});
// 同时输出压缩过的和未压缩版本的文件
gulp.task('rename', function () {
    return gulp.src('foo.js')
    // 这会输出一个未压缩过的版本
        .pipe(gulp.dest('dist/'))
        // 这会输出一个压缩过的并且重命名未 foo.min.js 的文件
        .pipe(uglify())
        .pipe(rename({extname: '.min.js'}))
        .pipe(gulp.dest('/dist'));
});
// css压缩,添加版本号
gulp.task('rename', function () {
    return gulp.src('*.css')
        .pipe(csso())
        // 此处不要修改文件名称,不然下面rev任务自动替换引用文件时会找不到要替换的内容
        //在输出文件之前执行rev(),输出后的文件就会生成hash码
        .pipe(rev())
        .pipe(gulp.dest('/dist'))
        .pipe(rev.manifest())//set hash key json
        .pipe(gulp.dest('/dist/rev/'));
});

// rev需要单独执行才能为HTML引入的文件自动加上版本号
gulp.task('rev', function () {
    return gulp.src(['rev/**/*.json', 'pages/**/*.html'])
        .pipe(revCollector({
            replaceReved: true
        }))
        .pipe(rename(function (path) {
            // path.basename += '.min';
            path.extname = '.html'
        }))
        .pipe(gulp.dest('/page-copy'));
});

//同步处理任务
gulp.task('default', gulpsync.sync(
    [
        'clean:mobile',
        ['less,js,css'],
        'rev'
    ]
))

 

转载于:https://my.oschina.net/u/3272730/blog/1580013

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值