使用gulp自動化打包合並前端靜態資源(CSS、JS文件壓縮、添加版本號)
現在正在做的項目更新叠代比較頻繁,會經常對前端代碼打包部署,手動整合代碼文件很麻煩並且浪費時間,所以決定使用gulp來代替手工完成這項工作。
前端靜態資源在發版更新時會面臨客戶端瀏覽器緩存的問題(可參考這篇文章),解決這個問題可以采用兩類方法:覆蓋方法(引用資源時加版本號,不修改資源文件名)、非覆蓋方法(修改資源文件名),本篇文章主要采用的是第一種加版本號的方式,主要用gulp給靜態資源自動加版本號和壓縮CSS、JS。
原理:通過對JS,CSS文件內容進行Hash運算,生成一個文件的唯一Hash字符串,若對文件內容進行了修改則Hash號會發生變化。在HTML中引用文件時將版本號加在後面。
原始HTML:
1 <link href="css/global.css" rel="stylesheet" type="text/css" /> 2 <script src="js/fun.js"></script>
使用後HTML:
1 <link href="css/global.css?v=b40a6f2a9f" rel="stylesheet" type="text/css" /> 2 <script src="js/fun.js?v=3a08b5fa87"></script>
一、環境配置(安裝gulp)
首先安裝node、npm(此處省略)
安裝gulp以及用到的插件,並在項目目錄下創建文件gulpfile.js。
$ npm install --global gulp --安裝全局gulp $ npm install --save-dev gulp $ npm install --save-dev gulp-rev $ npm install --save-dev gulp-rev-collector $ npm install --save-dev run-sequence $ npm install --save-dev gulp-clean $ npm install --save-dev gulp-minify-css $ npm install--save-dev gulp-uglify
在項目目錄下創建文件gulpfile.js
項目目錄結構:
node_modules中是安裝的gulp和各種插件
二、編寫gulpfile.js
1 //引入gulp和gulp插件 2 var gulp = require(‘gulp‘), 3 runSequence = require(‘run-sequence‘), 4 rev = require(‘gulp-rev‘), 5 clean = require(‘gulp-clean‘), 6 minifycss=require(‘gulp-minify-css‘), 7 uglify=require(‘gulp-uglify‘), 8 revCollector = require(‘gulp-rev-collector‘); 9 10 //定義css、js源文件路徑 11 var cssSrc = ‘./**/*.css‘, //選擇目錄下所有css 12 jsSrc = ‘./**/*.js‘, //選擇目錄下所有css 13 srcExclude = ‘!./node_modules/**/*‘, //排除node_modules中的文件 14 cssFile = ‘css/**/*‘, //css文件夾 15 imageFile = ‘image/**/*‘, //圖片文件夾 16 jsFile = ‘js/**/*‘, //js文件夾 17 jsCompressPath = ‘Publish/js/*.js‘, //壓縮Publish中的js 18 cssCompressPath = ‘Publish/css/*.css‘; //壓縮Publish中的css 19 20 21 //CSS生成文件hash編碼並生成 rev-manifest.json文件名對照映射 22 gulp.task(‘revCss‘, function(){ 23 return gulp.src([cssSrc, srcExclude]) 24 .pipe(rev()) 25 .pipe(rev.manifest()) 26 .pipe(gulp.dest(‘rev/css‘)); 27 }); 28 29 //js生成文件hash編碼並生成 rev-manifest.json文件名對照映射 30 gulp.task(‘revJs‘, function(){ 31 return gulp.src([jsSrc, srcExclude]) 32 .pipe(rev()) 33 .pipe(rev.manifest()) 34 .pipe(gulp.dest(‘rev/js‘)); 35 }); 36 37 38 //Html替換css、js文件版本 39 gulp.task(‘revHtml‘, function () { 40 return gulp.src([‘rev/**/*.json‘, ‘*.html‘]) 41 .pipe(revCollector()) 42 .pipe(gulp.dest(‘Publish‘)); 43 }); 44 45 //拷貝除HTML外其他的文件 46 gulp.task(‘copy‘, function(){ 47 return gulp.src([cssFile, jsFile, imageFile],{ base: ‘.‘}) 48 .pipe(gulp.dest(‘Publish‘)); 49 }); 50 51 //壓縮JS 52 gulp.task(‘jscompress‘, function(){ 53 return gulp.src(jsCompressPath) 54 .pipe(uglify()) 55 .pipe(gulp.dest("Publish/js")); 56 }); 57 58 //壓縮CSS 59 gulp.task(‘csscompress‘, function(){ 60 return gulp.src(cssCompressPath) 61 .pipe(minifycss()) 62 .pipe(gulp.dest("Publish/css")); 63 }); 64 65 //開發構建 66 gulp.task(‘dev‘, function (done) { 67 condition = false; 68 runSequence( 69 [‘clean‘], 70 [‘revCss‘], 71 [‘revJs‘], 72 [‘revHtml‘], 73 [‘copy‘], 74 [‘jscompress‘], 75 [‘csscompress‘], 76 done); 77 }); 78 79 gulp.task(‘clean‘, function(){ 80 gulp.src(‘rev‘,{read:false}).pipe(clean()); 81 return gulp.src(‘Publish‘,{read:false}).pipe(clean()); 82 }); 83 84 85 gulp.task(‘default‘, [‘dev‘]);
三、更改插件代碼
在項目目錄下直接執行gulp命令
$ gulp
會得到如下效果:
1 <link href="css/global-b40a6f2a9f.css" rel="stylesheet" type="text/css" /> 2 <script src="js/fun-3a08b5fa87.js"></script>
需要更改gulp-rev、rev-path、gulpl-rev-collector插件的代碼:
1.node_modules/gulp-rev/index.js
第135行:manifest[originalFile] = revisionedFile;
更改為:manifest[originalFile] = originalFile + ‘?v=‘ + file.revHash;
2.node_modules/rev-path/index.js
第9行:return modifyFilename(pth, (filename, ext) => `${filename}-${hash}${ext}`);
更改為:return modifyFilename(pth, (filename, ext) => `${filename}${ext}`);
3.node_modules/gulp-rev-collector/index.js
第40行:var cleanReplacement = path.basename(json[key]).replace(new RegExp( opts.revSuffix ), ‘‘ );
更改為:var cleanReplacement = path.basename(json[key]).split(‘?‘)[0];
這裏需要註意插件的版本不一樣,需要改動的地方會有不同;
本文這裏所有插件的版本為:
gulp@3.9.1 [email protected] [email protected] [email protected] run-sequence@2.2.1 gulp-clean@0.4.0 gulp-minify-css@1.2.4 gulp-uglify@3.0.0
改完之後的效果
1 <link href="css/global.css?v=b40a6f2a9f" rel="stylesheet" type="text/css" /> 2 <script src="js/fun.js?v=3a08b5fa87"></script>
四、小結
gulp的任務的執行是異步的,想要保證任務執行的順序,需要使用run-sequence插件
1 gulp.task(‘dev‘, function (done) { 2 condition = false; 3 runSequence( 4 [‘clean‘], 5 [‘revCss‘], 6 [‘revJs‘], 7 [‘revHtml‘], 8 [‘copy‘], 9 [‘jscompress‘], 10 [‘csscompress‘], 11 done); 12 });
這裏順序執行任務:
先清除舊的rev和Pulish文件夾及其目錄下所有文件(clean),之後生成CSS文件名對照映射的JSON文件(revCSS),再之後生成JS文件名對照映射的JSON文件(revJS),之後替換掉HTML中的鏈接,加上版本號(revHTML),將除了HTML之外其他的靜態資源拷貝到Publish中(copy),然後壓縮Publish/js中的JS文件,並將壓縮後的文件替換掉原來的未壓縮文件(jscompress),最後壓縮Publish/css中的CSS文件,並替換掉未壓縮文件(csscompress)。
PS:
1.在寫路徑時,"!"是排除的標識,可以排除一些文件,如:
gulp.src([‘./**/*.css‘, ‘!./node_modules/**/*‘])
這裏選中的文件就是除了node_modules中的其他文件夾下的CSS文件
2.拷貝時若要保持路徑,需要加一個base選項,即:
gulp.src(‘Publish/css/*.css‘,{ base: ‘.‘})
之後也可以分別對測試環境和生產環境編寫任務,使用命令分開打包。
使用gulp自動化打包合並前端靜態資源(CSS、JS文件壓縮、添加版本號)