1、前言

使用gulp解决RequireJS项目前端缓存问题(一)

使用gulp解决RequireJS项目前端缓存问题(二

前端缓存一直是个令人头疼的问题,你有可能见过下面博客园首页的资源文件链接:

有没有发现文件名后面有一串不规则的东东,没错,这就是运用缓存机制,我们今天研究的就是这种东西。

先堵为快,猛戳链接下载Demohttps://github.com/hua126mail/gulpRequireJsCache

以dist为根目录,运行http://localhost/html/index.html,如果出现“Good!成功加载index.js”,则表示成功了。

不熟悉gulp的同学,可以参考这个比较详细的教程:http://www.ydcss.com/archives/18

不熟悉RequireJS的同学,可以参考官方教程:http://www.requirejs.cn/

2、项目主要目录:

  gulpRequireJsCache
  |
  |-- dist          //存放发布的文件
  |
  |-- rev          //存放控制版本号的 rev-manifest.json
  |
  |-- src          //项目源文件
  |
  |-- gulpfile.js     //gulp主文件,定义的任务都在这里
  |
  |-- package.json    //gulp依赖包配置文件
  |
  |-- landing.html
  根据执行命令npm install --save-dev后,主目录下会多一个node_modules文件夹,至此,gulp基本配置完成。

  gulpfile文件:
var gulp = require('gulp'),
sass = require('gulp-sass'), //编译sass
cssmin = require('gulp-clean-css'), //压缩css
autoprefixer = require('gulp-autoprefixer'), //添加浏览器前缀
rev = require('gulp-rev'), //添加版本号
revCollector = require('gulp-rev-collector'), //添加版本号
clean = require('gulp-clean'), //清理文目标文件夹
csso = require('gulp-csso'), //合并css属性
csslint = require('gulp-csslint'), //css语法检查
csscomb = require('gulp-csscomb'), //css 样式表的各属性的顺序
imagemin = require('gulp-imagemin'), //图片压缩
cache = require('gulp-cache'), //缓存处理
htmlmin = require('gulp-htmlmin'), //压缩html
replace = require('gulp-replace'), //替换路径
uglify = require('gulp-uglify'), //压缩js
jshint = require('gulp-jshint') //js语法检查
; gulp.task("cleanCss",function(){
return gulp.src('dist/css',{read:false})
.pipe(clean());
}); gulp.task('sass', ['cleanCss'],function () { //执行完cleanCss任务后再执行sass任务
gulp.src('src/sass/**/*.scss')
.pipe(sass())
.pipe(cssmin())
.pipe(autoprefixer())
//.pipe(csscomb())
.pipe(csso())
.pipe(csslint())
.pipe(rev())
.pipe(gulp.dest('dist/css'))
.pipe(rev.manifest())//- 生成一个rev-manifest.json
.pipe(gulp.dest('rev/css')); }); gulp.task("cleanImg",function(){
return gulp.src('dist/img',{read:false})
.pipe(clean());
}); gulp.task('imgmin',['cleanImg'], function () {
gulp.src('src/img/**/*.{png,jpg,gif,ico}')
.pipe(cache(imagemin())) //没有修改的图片直接从缓存文件读取
.pipe(rev())
.pipe(gulp.dest('dist/img'))
.pipe(rev.manifest())//- 生成一个rev-manifest.json
.pipe(gulp.dest('rev/img'));
}); gulp.task("cleanJs",function(){
return gulp.src(['dist/js/*','!dist/js/lib'],{read:false})
.pipe(clean());
}) gulp.task('jsmin', ['cleanJs'], function () {
gulp.src(['src/js/**/*.js','!src/js/**/*.min.js'])
.pipe(jshint())
.pipe(uglify())
.pipe(rev({merge:true}))
.pipe(gulp.dest('dist/js'))
.pipe(rev.manifest())//- 生成一个rev-manifest.json
.pipe(gulp.dest('rev/js')); gulp.src(['src/js/lib/**/*.js'])
.pipe(gulp.dest('dist/js/lib'))
}); gulp.task('htmlmin',function () {
var options = {
removeComments: true,//清除HTML注释
//collapseWhitespace: true,//压缩HTML
removeEmptyAttributes: true,//删除所有空格作属性值 <input id="" /> ==> <input />
minifyJS: true,//压缩页面JS
minifyCSS: true//压缩页面CSS
};
gulp.src('src/html/**/*.html')
.pipe(htmlmin(options))
.pipe(rev())
.pipe(gulp.dest('dist/html'))
.pipe(rev.manifest())//- 生成一个rev-manifest.json
.pipe(gulp.dest('rev/html'));
}); gulp.task('replaceURL', function(){
gulp.src(['dist/html/**/*.html'])
.pipe(replace('../css', '/css'))
.pipe(replace('../js', '/js'))
.pipe(replace('/src', '/dist'))
.pipe(gulp.dest('dist/html')); gulp.src(['dist/css/**/*.css'])
.pipe(replace('../css', '/css'))
.pipe(replace('../js', '/js'))
.pipe(replace('/src', '/dist'))
.pipe(gulp.dest('dist/css')); gulp.src(['dist/js/**/*.js'])
.pipe(replace('../css', '/css'))
.pipe(replace('../js', '/js'))
.pipe(replace('/src', '/dist'))
.pipe(gulp.dest('dist/js')); }); gulp.task('revUrl', function() {
gulp.src(['rev/{css,img,js}/*.json', 'dist/html/**/*.html']) //- 读取 rev-manifest.json 文件以及需要进行css名替换的文件
.pipe(revCollector()) //- 执行文件内css名的替换
.pipe(gulp.dest('dist/html')); //- 替换后的文件输出的目录 gulp.src(['rev/{css,img,js}/*.json', 'dist/css/**/*.css']) //- 读取 rev-manifest.json 文件以及需要进行css名替换的文件
.pipe(revCollector()) //- 执行文件内css名的替换
.pipe(gulp.dest('dist/css')); //- 替换后的文件输出的目录 gulp.src(['rev/{css,img,js}/*.json', 'dist/js/**/*.js']) //- 读取 rev-manifest.json 文件以及需要进行css名替换的文件
.pipe(revCollector()) //- 执行文件内css名的替换
.pipe(gulp.dest('dist/js')); //- 替换后的文件输出的目录 }); gulp.task("autowatch",function(){
gulp.watch(['src/sass/**/*.scss'],['sass']); //监听sacc文件改变后,编译、去缓存
}); /*
* 单步步骤:
* 1.gulp sass 编译scss文件
* 2.gulp jsmin 压缩js
* 3.gulp imgmin 压缩图片
* 4.gulp htmlmin 压缩HTML文件
* 5.gulp replaceURL 替换相对路径为绝对路径
* 6.gulp revUrl 引用manifest给HTML添加版本号
*
*
* gulp sass jsmin htmlmin imgmin replaceURL revUrl
*
*
*
* 如果改了scss文件:则执行:gulp sass
* 如果改了js文件:则执行:gulp jsmin
* 如果改了img文件:则执行:gulp imgmin
*
* 只要改了HTML引用到的资源文件,最后都需要执行gulp htmlmin,gulp replaceURL,gulp revUrl,以清理缓存
* */

根据最后的单步步骤,我们来一步步解剖说明:

var gulp = require('gulp'),
sass = require('gulp-sass'), //编译sass
cssmin = require('gulp-clean-css'), //压缩css
autoprefixer = require('gulp-autoprefixer'), //添加浏览器前缀
rev = require('gulp-rev'), //添加版本号
revCollector = require('gulp-rev-collector'), //添加版本号
clean = require('gulp-clean'), //清理文目标文件夹
csso = require('gulp-csso'), //合并css属性
csslint = require('gulp-csslint'), //css语法检查
csscomb = require('gulp-csscomb'), //css 样式表的各属性的顺序
imagemin = require('gulp-imagemin'), //图片压缩
cache = require('gulp-cache'), //缓存处理
htmlmin = require('gulp-htmlmin'), //压缩html
replace = require('gulp-replace'), //替换路径
uglify = require('gulp-uglify'), //压缩js
jshint = require('gulp-jshint') //js语法检查
;

这些都是执行任务时要用到的插件,看注释大概就知道是干嘛的了。

2.1、css相关处理:运行“gulp sass”

gulp.task("cleanCss",function(){
return gulp.src('dist/css',{read:false})
.pipe(clean());
}); gulp.task('sass', ['cleanCss'],function () { //执行完cleanCss任务后再执行sass任务
gulp.src('src/sass/**/*.scss')
.pipe(sass())
.pipe(cssmin())
.pipe(autoprefixer())
//.pipe(csscomb())
.pipe(csso())
.pipe(csslint())
.pipe(rev())
.pipe(gulp.dest('dist/css'))
.pipe(rev.manifest())//- 生成一个rev-manifest.json
.pipe(gulp.dest('rev/css')); });

gulp.task("autowatch",function(){
  gulp.watch(['src/sass/**/*.scss'],['sass']); //监听sacc文件改变后,编译、去缓存
});

因为公司项目用的是sass,所以加了一个监听任务,去编译生成css文件,css发生更改之后先执行“cleanCss”任务,清空dist文件夹下的css文件,重点是后面的.pipe(rev.manifest()),这一步将生成一个资源文件路径的rev-manifest.json文件,里面的内容是这样的:

{
"base/base.css": "base/base-c1e638e1f6.css",
"controller/index.css": "controller/index-1454781768.css"
}

没错,这是用来最后在HTML文件替换css引用路径的。

同时,dist/css目录下也生成对应的文件:

2.2、img相关处理:运行“gulp imgmin”

gulp.task("cleanImg",function(){
return gulp.src('dist/img',{read:false})
.pipe(clean());
}); gulp.task('imgmin',['cleanImg'], function () {
gulp.src('src/img/**/*.{png,jpg,gif,ico}')
.pipe(cache(imagemin())) //没有修改的图片直接从缓存文件读取
.pipe(rev())
.pipe(gulp.dest('dist/img'))
.pipe(rev.manifest())//- 生成一个rev-manifest.json
.pipe(gulp.dest('rev/img'));
});

过程就不多说啦,一样的先清空dist的图片文件夹,压缩图片,生成rev-manifest.json,生成的文件如下:

{
"push-bg.jpg": "push-bg-6179117417.jpg"
}

  

2.3、js相关处理:运行“gulp jsmin”

gulp.task('jsmin', ['cleanJs'], function () {
gulp.src(['src/js/**/*.js','!src/js/**/*.min.js'])
.pipe(jshint())
.pipe(uglify())
.pipe(rev({merge:true}))
.pipe(gulp.dest('dist/js'))
.pipe(rev.manifest())//- 生成一个rev-manifest.json
.pipe(gulp.dest('rev/js')); gulp.src(['src/js/lib/**/*.js'])
.pipe(gulp.dest('dist/js/lib'))
});

过程就是检查语法,压缩,生成rev-manifest.json,要注意的地方是min类型的文件是放在lib目录下,是不需要压缩处理的,直接拷贝过去即可。生成的rev-manifest.json文件如下:

{
"base/cal.js": "base/cal-2e41f44581.js",
"base/require-config.js": "base/require-config-3c5aeda076.js",
"controller/index.js": "controller/index-d14ed3eca8.js"
}

2.4、js相关处理:运行“gulp htmlmin”

gulp.task('htmlmin',function () {
var options = {
removeComments: true,//清除HTML注释
//collapseWhitespace: true,//压缩HTML
removeEmptyAttributes: true,//删除所有空格作属性值 <input id="" /> ==> <input />
minifyJS: true,//压缩页面JS
minifyCSS: true//压缩页面CSS
};
gulp.src('src/html/**/*.html')
.pipe(htmlmin(options))
.pipe(rev())
.pipe(gulp.dest('dist/html'))
});

过程省略一百字。。。

2.5、替换相对路径:运行“gulp replaceURL”

gulp.task('replaceURL', function(){
gulp.src(['dist/html/**/*.html'])
.pipe(replace('../css', '/css'))
.pipe(replace('../js', '/js'))
.pipe(replace('/src', '/dist'))
.pipe(gulp.dest('dist/html')); gulp.src(['dist/css/**/*.css'])
.pipe(replace('../css', '/css'))
.pipe(replace('../js', '/js'))
.pipe(replace('/src', '/dist'))
.pipe(gulp.dest('dist/css')); gulp.src(['dist/js/**/*.js'])
.pipe(replace('../css', '/css'))
.pipe(replace('../js', '/js'))
.pipe(replace('/src', '/dist'))
.pipe(gulp.dest('dist/js')); });

过程就是替换所有文件的相对路径为绝对路径。

2.6、替换资源文件引用(重中之重):运行“gulp revUrl”

gulp.task('revUrl', function() {
gulp.src(['rev/{css,img,js}/*.json', 'dist/html/**/*.html']) //- 读取 rev-manifest.json 文件以及需要进行css名替换的文件
.pipe(revCollector()) //- 执行文件内css名的替换
.pipe(gulp.dest('dist/html')); //- 替换后的文件输出的目录 gulp.src(['rev/{css,img,js}/*.json', 'dist/css/**/*.css'])
.pipe(revCollector())
.pipe(gulp.dest('dist/css')); gulp.src(['rev/{css,img,js}/*.json', 'dist/js/**/*.js'])
.pipe(revCollector())
.pipe(gulp.dest('dist/js')); });

3、测试结果:

打开dist/html/index.html

<!doctype html>
<html>
<head>
<title>requirejs</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/css/base/base-c1e638e1f6.css">
<link rel="stylesheet" type="text/css" href="/css/controller/index-1454781768.css">
<!--[if IE]>
<link rel="stylesheet" type="text/css" href="/csstest/main.css"/>
<![endif]-->
</head>
<body>
<div class="main border-grey" id="name1">
<div class="wrapper">未加载 index.js</div>
</div> <script type="text/javascript" src="/js/base/require-config-3c5aeda076.js" defer="true"></script>
<script data-main="/js/controller/index-d14ed3eca8.js" src="/js/lib/require.min.js" defer="true"></script>
</body>
</html>

可以看到,css和js文件引用的路径都替换成了相应rev-manifest.json中的值。

访问一下页面:

控制台也显示资源文件引用正常:

3.1、修改测试

修改base.scss中body{font-size: 14px;}的字体为20px,重新执行gulp,再截图看下控制台:

可以发现,除了base.css引用变了之外,其他保持不变。

4、补充:

按上面的步骤走完,gulp已经满足项目基本需要了,但仍存在两点问题:

  1. 对通过require-config.js引入的js文件修改后,没有更新到
  2. 每次gulp运行完后都会生成新的文件,开发环境是做了清除dist目录处理,但对于一般公司服务器而言,发布到生产环境上,不可能每次发布都对dist做清空处理,文件只会越积越多
  3. 咦,怎么跟前言博客园截图引用的方法不一样。。。

上面这3点,将在下一节中详解。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

欢迎转载,转载请注明作者:飘飞的夏秋 和出处 http://www.cnblogs.com/chenchenghua/p/5953767.html

使用gulp解决RequireJS项目前端缓存问题(一)的更多相关文章

  1. 使用gulp解决RequireJS项目前端缓存问题(二)

    1.前言 这一节,我们主要解决在上一节<使用gulp解决RequireJSs项目前端缓存问题(一)>末尾提到的几个问题: 对通过require-config.js引入的js文件修改后,没有 ...

  2. gulp解决RequireJS

    gulp解决RequireJS项目前端缓存问题(二)   前言 这一节,我们主要解决在上一节<使用gulp解决RequireJSs项目前端缓存问题(一)>末尾提到的几个问题: 对通过req ...

  3. 利用gulp解决微信浏览器缓存问题

    做了好多项目,这次终于要解决微信浏览器缓存这个令人头疼的问题了.每次上传新的文件,在微信浏览器中访问时,总要先清除微信的缓存,实在麻烦,在网上搜罗了很多解决办法,终于找到了方法:利用gulp解决缓存问 ...

  4. Gulp解决发布线上文件(CSS和JS)缓存问题

    Gulp解决发布线上文件(CSS和JS)缓存问题 本文的缘由:目前经常线上发布文件后要不断的刷新页面及过很长时间,页面上的CSS和JS文件才能生效,特别对于目前做微信商城的时候,微信内置的浏览器缓存非 ...

  5. Angular企业级开发(6)-使用Gulp构建和打包前端项目

    1.gulp介绍 基于流的前端自动化构建工具,利用gulp可以提高前端开发效率,特别是在前后端分离的项目中.使用gulp能完成以下任务: 压缩html.css和js 编译less或sass等 压缩图片 ...

  6. 通过gulp为requireJs引入的模块添加版本号

    由于项目用到requireJs,并且通过gulp来对项目进行统一的管理,为了防止浏览器对文件进行缓存,所以通过gulp为项目中的文件添加版本号. 1.分别安装gulp-rev.gulp-rev-col ...

  7. 使用gulp解决外部编辑器修改Eclipse文件延迟更新的问题

    本人前端用惯了Hbuilder,修改了eclipse项目中的文件后,由于是外部编辑器修改过的,eclipse不会自动部署更新,一般按F5刷新项目,或者在 preferences > genera ...

  8. gulp进阶构建项目由浅入深

    gulp进阶构建项目由浅入深 阅读目录 gulp基本安装和使用 gulp API介绍 Gulp.src(globs[,options]) gulp.dest(path[,options]) gulp. ...

  9. 使用gulp打包普通项目

    前言: 在使用gulp打包工具之前,我做的H5项目在浏览器中的缓存是很严重的,若改了一点css,加了一句js代码,不手动清除浏览器缓存是看不到效果的.老总也在项目演示当中遇到这些问题,一查找原因却是缓 ...

随机推荐

  1. 如何利用 Visual Studio 自带工具提高开发效率

    Visual Stuido 是一款强大的Windows 平台集成开发工具,你是否好好地利用了它呢? 显示行号 有些时候(比如错误定位)的时候,显示行号将有利于我们进行快速定位. 如何显示 1. 工具 ...

  2. Java发送Http请求并获取状态码

    通过Java发送url请求,查看该url是否有效,这时我们可以通过获取状态码来判断. try { URL u = new URL("http://10.1.2.8:8080/fqz/page ...

  3. 解析大型.NET ERP系统数据访问 对象关系映射框架LLBL Gen Pro

    LLBL Gen Pro是一个为.NET开发人员设计的的对象关系映射(ORM)框架,与NHibernate,Entity Framework等框架一样,通过实体与数据表的映射,实现关系数据库持久化. ...

  4. 【Win 10应用开发】响应系统回退键的导航事件

    按例,老周今天要讲一个故事,这个故事之前老周在微博上分享过.大伙知道在8.1的时候,有一个扩展类库——NotificationExtensions,可以真TMD轻松生成通知XML模板,其实,这个类库也 ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统(2)-easyui构建前端页面框架[附源码]

    系列目录 前言 为了符合后面更新后的重构系统,本文于2016-10-31日修正一些截图,文字 我们有了一系列的解决方案,我们将动手搭建新系统吧. 后台系统没有多大的UI视觉,这次我们采用的是标准的左右 ...

  6. windows 环境下nginx + tomcat群 + redis 实现session共享

    nginx作为负载均衡根据定义将不同的用户请求分发到不同的服务器,同时也解决了因单点部署服务器故障导致的整个应用不能访问的问题 在加入nginx之后,如果多个服务器中的一个或多个(不是全部)发生故障, ...

  7. 时间复杂度分别为 O(n)和 O(1)的删除单链表结点的方法

    有一个单链表,提供了头指针和一个结点指针,设计一个函数,在 O(1)时间内删除该结点指针指向的结点. 众所周知,链表无法随机存储,只能从头到尾去遍历整个链表,遇到目标节点之后删除之,这是最常规的思路和 ...

  8. Bootstrap框架的学习(二)

    一.下载Bootstrap Bootstrap (当前版本 v3.3.0)提供以下几种方式帮你快速上手,每一种方式针对具有不同技能等级的开发者和不同的使用场景. 下载地址:http://v3.boot ...

  9. Mybatis框架 的快速入门

    MyBatis 简介 什么是 MyBatis? MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及结果 ...

  10. 利用Python进行数据分析 基础系列随笔汇总

    一共 15 篇随笔,主要是为了记录数据分析过程中的一些小 demo,分享给其他需要的网友,更为了方便以后自己查看,15 篇随笔,每篇内容基本都是以一句说明加一段代码的方式, 保持简单小巧,看起来也清晰 ...