使用前端构建工具批量为页面中引用的js文件添加版本号的历程

37 篇文章 0 订阅
33 篇文章 0 订阅

近日遇到有客户反应,页面打开显示不正常,不能完全的显示出页面。细问之下才得知,原来是有一个js文件修改了一个方法,但是上线后由于浏览器缓存的原因,还是加载的旧js文件,导致页面显示不正常了。给客户解释由于系统更新,需要强制刷新才可以。这天陆续又有客户反映遇到此问题,而有些客户由于对电脑了解的少,你说强制刷新他也不知怎么操作。思考是不是由网站自己解决此问题。先是考虑在页面引用的js文件后面加随机数来解决,但是考虑到该js文件引用频繁,如果每次都请求服务器,对服务器压力比较大,考虑着用版本号的方式在引用的时候实现,这样每次js文件有改变就更改版本号。如果js文件不改变,由于请求的还是原地址,这样就会从本地浏览器缓存中读取,而不会增加服务器负担。

原csthml中的js引用代码:

<script src="~/Scripts/app/member/practice.js"></script>
<script src="~/Areas/MM/Scripts/practice.js"></script>

更改后的js引用代码:

<script src="~/Scripts/app/member/practice.js?v=1.0"></script>
<script src="~/Areas/MM/Scripts/practice.js?v=1.0"></script>

在网站中更改后才发现,貌似页面还不少,需要更改8个页面,这样如果每次更改都要找这8个页面,感觉有点麻烦,也不利于以后的扩展,就考虑着找一个能批量更改的工具。这一找,还真找到一个:

找到一篇 gulp 自动添加版本号。由于以前装过 nodejs 及 npm ,也知道 gulp ,但是在实际的项目中从来没有使用过,就想着这次趁着这次的需求,研究下。在研究的过程中发现,想实际应用也不是那么容易,中间要学习许多知识。由于考虑到第一次研究,关注点就集中到一点,就是解决js文件的版本问题。但即使这样,前前后后也费了将近5天的时间。中间历经了许多问题。在这里记录下,便于以后查找。

npm随着nodejs安装一起就安装了。由于nodejs安装的早,怕npm的版本过老,先更新了下npm的版本。用win+R打开运行窗口,输入cmd,打开cmd窗口。输入命令:

npm install -g npm

安装后运行 npm -v 查看 npm 的版本,是 4.5.0 版。

一、在cmd窗口中利用 cd 命令转到网站项目的根目录。然后运行命令

npm install module_name 

此命令在项目中会创建一个名字为 node_modules 的模块。项目中需要的其他插件安装都会安装到这个文件夹底下。

二、在项目根目录创建package.json文件。这个是必须的,项目的基本信息及安装到项目中的其他插件版本号都会存在这里面。

运行命令:

npm init

此命令会创建 package.json 文件,运行此命令后,在 cmd 窗口中会显示 name ,version ,description 等,等待你的输入,这里name必须输入,而且不能有大写字母,其他自己看着填写,如果实在不知怎么填,留空。

填写完成后我的 package.json 文件如下:

{
  "name": "lmsoft.web",
  "version": "1.0.0",
  "description": "交规培训",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "sxf359",
  "license": "ISC",
  
}

三、全局安装 gulp :

npm install -g gulp

然后在项目目录再次安装 gulp :

npm install --save-dev gulp

这里为了把 gulp 写进项目 package.json 文件的依赖中, 加上了 --save-dev

至于为什么在全局安装gulp后,还需要在项目中本地安装一次,有兴趣的可以看下 stackoverflow 上有人做出的回答: why-do-we-need-to-install-gulp-globally-and-locally、what-is-the-point-of-double-install-in-gulp 。大体就是为了版本的灵活性,但如果没理解那也不必太去纠结这个问题,只需要知道通常我们是要这样做就行了。

四、在项目目录下分别安装gulp-rev、gulp-rev-collerctor 、run-sequence

npm install --save-dev gulp-rev
npm install --save-dev gulp-rev-collector

npm install -- save -dev run -sequence

都安装完后我的 gulp 版本:3.9.1

gul-rev 版本:7.1.2

gulp-rev-collector: 1.1.1
run-sequence: 1.2.2

五、由于默认的 gulp 添加版本号的方法是直接更改 js 或 css 文件名,并不适用我的需求,因此要更改相应的文件。

打开网站项目目录下的 node_modules\gulp-rev\index.js 文件,搜索代码:manifest[originalFile] = revisionedFile

找到后注释掉此行,然后在下面另起一行,写如下代码:


manifest[originalFile] =originalFile + '?v=' +file.revHash;


这个格式就是我们需要的格式。

打开node_modules\gulp-rev-collector\index.js,搜索代码:path.basename(json[key]).replace(new RegExp( opts.revSuffix ), '' )

找到:

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


注释掉,然后在这行下面写新代码:

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


再在此页面中搜索代码:new RegExp('([\/\\\\\'"])' + pattern + '(\\?v=\\w{10})?', 'g')

搜索到此行:

regexp: newRegExp('([\/\\\\\'"])' +pattern, 'g'),

此行替换为:

regexp: newRegExp('([\/\\\\\'"])' +pattern, 'g'),


由于这里的更改方法是在http://blog.csdn.net/zchcode/article/details/52421871这篇文章找到的,但是由于要替换的内容与我实际遇到的有所不同,导致后续出现错误,不能替换。这里暂且不说。


六、在网站项目根目录创建 gulpfile.js 空文件。

输入以下代码:

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

//定义js源文件路径
var jsSrc = "Scripts/app/member/practice.js";
//js生成文件hash编码并生成 rev-manifest.json文件名对照映射
gulp.task('revJs', function () {
    return gulp.src(jsSrc)
        .pipe(rev())
        .pipe(rev.manifest())
        .pipe(gulp.dest('rev/js'));
});

//Html替换js文件版本
gulp.task('revCshtml', function () {
    return gulp.src(['rev/js/rev-manifest.json', 'views/member/*.cshtml'])          
        .pipe(revCollector())
        .pipe(gulp.dest('views/member'));
});

//开发构建
gulp.task('dev', function (done) {
    condition = false;
    runSequence(        
        ['revJs'],
        ['revCshtml'],
        done);
});

gulp.task('default', ['dev']);

这个文件代码也参考了http://blog.csdn.net/zchcode/article/details/52421871 文件中的相关代码,结合了自己项目的实际情况进行了修改。这里对代码的功能进行一些解释。


gulp.task('revJs', function () {
    return gulp.src(jsSrc)
        .pipe(rev())
        .pipe(rev.manifest())
        .pipe(gulp.dest('rev/js'));
});

这段代码, gulp.src是打开相应的js文件,pipe(rev()),执行 gulp-rev插件,pipe(rev.manifest()) 生成 rev-mainfest.json文件,pipe(gulp.dest('rev/js')),生成的rev-mainfest.json文件存入项目根目录下的 rev/js 目录下面。

如果在cmd窗口执行

gulp revJs

则会执行revJs任务,生成的rev-mainfest.json文件代码如下:

{
  "practice.js": "practice.js?v=0f74d71923"
}

这里要注意,revJs区分大小写,如果你纯小写,此任务不会执行,会提示:

Task 'revjs' is not  your gulpfile.js中


gulp.task('revCshtml', function () {
    return gulp.src(['rev/js/rev-manifest.json', 'views/member/*.cshtml'])          
        .pipe(revCollector())
        .pipe(gulp.dest('views/member'));
});

这个gulp任务是为了根据已经生成的rev-manifest.json文件,遍历views/member下的cshtml文件,并搜索practice.js?v=1.0,然后替换为practice.js?v=0f74d71923

gulp.task('dev', function (done) {
    condition = false;
    runSequence(        
        ['revJs'],
        ['revCshtml'],
        done);
});

此任务是按照先后顺序,先执行revJs 任务,再执行 revCshtml 任务。因为 gulp 的任务执行是多线程并行的,而 revJs 与revCshtml有先后的次序,才需要这样写。

至于gulp.task('default', ['dev']); 则是以默认任务的形式执行 dev 任务。即在cmd窗口的项目目录下面,输入:

gulp 

则直接执行dev 任务。

这里执行后发现,rev-manifest.json 被生成,但是 views/member 目录下的cshtml文件中含有

<script src="~/Scripts/app/member/practice.js?v=1.0"></script> 的部分却被转换成了 <script src="~/Scripts/app/member/practice.js?v=0f74d71923?v=1.0"></script> ,显然匹配规则出了问题。经过反复修改,最终

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

被修改为:

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

这样才正确替换了cshtml 文件中的  practice.js 相关代码。

替换后很欢喜,然后在网页中进行访问,却发现在不含practice.js 的 cshtml 文件中出现了左括号“(”缺少对应的右括号“)”这样的错误。 经过查看分析,发觉是该页面的 cshtml 文件中的else if (Model.Role == "科目四") 没有正确解析,出现的是乱码。 首先想到是文件编码问题,然后经过查看文件编码,是 utf8 格式, 但是我们知道, cshtml 文件格式是 utf8+BOM 的编码。真是一波未平,一波又起。经过百度,google搜索答案,但并没有可用的答案,只是有人提出是编码问题,需要转换,但并没有说明如何转换。

在网上搜索到 gulp-convert-encoding  这个插件,可用从一个编码转换到另一个编码。找到了这个插件的官方文档页面:

https://www.npmjs.com/package/gulp-convert-encoding

看了这个插件的示例:

var gulp = require('gulp');
var convertEncoding = require('gulp-convert-encoding');
 
gulp.task('default', function () {
    return gulp.src('src/file.txt')
        .pipe(convertEncoding({to: 'iso-8859-15'}))
        .pipe(gulp.dest('dist'));
});

觉得应用比较简单,可能会解决我的问题。然后在cmd窗口的项目目录下执行:

npm install --save-dev gulp-convert-encoding


然后在gulpfile.js文件的代码:

.pipe(gulp.dest('views/member'));

上面增加:

.pipe(convertEncoding({ to: 'utf-8+BOM' }))

执行,直接报错,这好理解,表示支持 cshtml 的带签名的 utf8 的编码字符串不是这样写的。因为示例很简单,只能根据官方文档一次一次的试错。最终经过n次尝试,终于找到了可行的代码:

.pipe(convertEncoding({ iconv: { decode: {}, encode: { addBOM: true}}, to: "utf8" }))

通过执行,这次解决了此问题,经过转换,可以转换为vs 认可的带签名的 utf8 编码格式。网页没有问题了。并且经过试验,也证实了只要 practice.js 文件有修改,v=后面的hash值就会改变。最终完整的我的gulpfile.js文件是这样的:

//引入gulp及gulp插件
var gulp = require("gulp"),
    runSequence = require('run-sequence'),
    rev = require('gulp-rev'),
    revCollector = require('gulp-rev-collector');
var convertEncoding = require('gulp-convert-encoding');

//定义js源文件路径
var jsSrc = "Scripts/app/member/practice.js";
var jsSrcmm = "areas/mm/Scripts/practice.js";
//js生成文件hash编码并生成 rev-manifest.json文件名对照映射
gulp.task('revJs', function () {
    return gulp.src(jsSrc)
        .pipe(rev())
        .pipe(rev.manifest())
        .pipe(gulp.dest('rev/js'));
});

gulp.task('revmmJs', function () {
    return gulp.src(jsSrcmm)
        .pipe(rev())
        .pipe(rev.manifest())
        .pipe(gulp.dest('rev/jsmm'));
});


//Html替换js文件版本
gulp.task('revCshtml', function () {
    return gulp.src(['rev/js/rev-manifest.json', 'views/member/*.cshtml'])          
        .pipe(revCollector())
        //.pipe(convertEncoding({ to: 'utf-8+BOM' }))
        .pipe(convertEncoding({ iconv: { decode: {}, encode: { addBOM: true}}, to: "utf8" }))
        .pipe(gulp.dest('views/member'));
});
//Html替换js文件版本
gulp.task('revMmCshtml', function () {
    return gulp.src(['rev/jsmm/rev-manifest.json', 'areas/mm/views/member/*.cshtml'])  
        .pipe(revCollector())
        .pipe(convertEncoding({ iconv: { decode: {}, encode: { addBOM: true } }, to: "utf8" }))
        .pipe(gulp.dest("areas/mm/views/member"));
});


//开发构建
gulp.task('dev', function (done) {
    condition = false;
    runSequence(        
        ['revJs'],
        ['revCshtml'],
        done);
});

gulp.task('devmm', function (done) {
    condition = false;
    runSequence(
        ['revmmJs'],
        ['revMmCshtml'],
        done);
});


gulp.task('default', ['dev','devmm']);
//gulp.task('default', function () {
//    console.log('hello world');
//});



  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值