前段時間公司作網站的優化,其中就有將HTML文件中用到的多個JS壓縮成一個min.js。如今作一個總結:javascript
css js 壓縮用的是 gulp,只要寫一個gulpfile.js腳本便可,很是方便css
css 目前只是將每一個源CSS文件壓縮了一下,沒有進行合併。 JS 作了兩步工做
A. 將每一個源JS文件壓縮html
這個簡單,不細說,下面會貼出代碼。 gulp.task('minifyjs-root',fistGulpTask, function() { return gulp.src(rootDir+'/*.js').pipe(gulp.dest(rootDir+'js')).pipe(rename({suffix: ''})).pipe(uglify()).pipe(gulp.dest(rootDir+'js')); });
B. 將HTML文件中包含的JS合併爲一個JS而且進行壓縮java
我當時第一個想法就是先將HTML文件用到的JS手動找出來放到gulpfile.js中的一個數組中,而後再將它合併成一個min.js。 如HTML文件中包含myjs1.js, myjs2.js, myjs3.js,要將它們合併壓縮爲myjs.min.js.
源HTML文件(本地開發文件) <!-- JS_MERGE_FLAG:this is flag for js files join to one min.js --> <script type="text/javascript" src="sresource/js/myjs1.js"></script> <script type="text/javascript" src="sresource/js/myjs2.js"></script> <script type="text/javascript" src="sresource/js/myjs3.js"></script>
合併壓縮爲myjs.min.js(發佈文件) <!-- JS_MERGE_FLAG:this is flag for js files join to one min.js --> <script type="text/javascript" src="sresource/js/myjs.min.js"></script>
能夠發現這種作法會致使本地開發環境的HTML文件與發佈時的不同。那就有下列問題 1.發佈時手動來修改HTML文件嗎?(將引用的JS修改成myjs.min.js) 2.當開發新功能時HTML要增長JS,那我就要修改gulpfile.js中的那個數組。 3.當有多個HTML文件要合併壓縮引用到的JS,那就要在gulpfile.js文件中維護多個數組。 4.當有部署時有使用jenkins打包(不能手動修改HTML文件)時,我應該怎麼辦。維護兩個HTML, 一個是本地開發環境的HTML,另外一個是發佈的? 發現有這些問題的存在將使得工程難以維護,或者說發佈時膽戰心驚。 當時有發現gulp是構建在node.js基礎上的,那麼能不能讓nodejs去查找html文件中引用了哪些js,而且將它們提取出來。 最後用它修改HTML文件(爲發佈文件)。好!有想法,那就試一試唄。下面是個人代碼。能夠實現這個功能。
//gulpfile.js var gulp = require('gulp'), minifycss = require('gulp-minify-css'), concat = require('gulp-concat'), uglify = require('gulp-uglify'), rename = require('gulp-rename'), jshint=require('gulp-jshint'); var glpTask = ['minifycss','minifyjs-root']; //var glpTask = []; var fistGulpTask=[]; var fs = require('fs'); var path = require('path'); var rootDir = 'src/main/webapp/sresource/'; //這個目錄下有 js html css 文件夾 var tmpDir = 'src/main/webapp/tmpjs'; var webappDir = 'src/main/webapp/'; var sourceDir = rootDir+'js'; var destDir = sourceDir; funcCompressJs(); function funcGulp(){ gulp.task('minifycss', fistGulpTask, function() { return gulp.src([rootDir+'css/*.css',rootDir+'css/*/*.css']) .pipe(rename({suffix: ''})) .pipe(minifycss()) .pipe(gulp.dest(rootDir+'css/')); }); gulp.task('minifyjs-root',fistGulpTask, function() { return gulp.src(rootDir+'js'+'/*.js').pipe(gulp.dest(rootDir+'js')).pipe(rename({suffix: ''})).pipe(uglify()).pipe(gulp.dest(rootDir+'js')); }); // 其它壓縮任務 gulp.task('default',[],function() { gulp.start(fistGulpTask.concat(glpTask)); }); } function funcCompressJs() { for (i = 0; i < joinJsHtml.length; i++) { funcHtmlJoinJsPro(webappDir + joinJsHtml[i]); } funcGulp(); } //js合併 function funcJsMerge(taskName, srcJs, targetJs){ console.log("taskName:"+taskName+", targetJs:"+targetJs); console.log("source js files:"); for(var i=0; i<srcJs.length; i++){ console.log(" "+srcJs[i]); } gulp.task(taskName, function(){ return gulp.src(srcJs) //須要操做的文件 .pipe(concat(targetJs)) //合併全部js到main.js .pipe(gulp.dest(rootDir+'js')) //輸出到文件夾 .pipe(rename({suffix: '.min'})) //rename壓縮後的文件名 .pipe(uglify()) //壓縮 .pipe(gulp.dest(rootDir+'js')); //輸出 }); } //要合併JS的HTML var jsMergeFg = "JS_MERGE_FLAG"; //<!--JS_MERGE_FLAG-->這個標誌意味着從這裏開始的JS 要合併爲一個 var joinJsHtml = ["mb.html"]; //要進行JS合併的HTML文件 function funcHtmlJoinJsPro(file) { var readmaxLen = 3072; var writeBuffer; var readBuffer = new Buffer(readmaxLen); var strReadBuf; var taskName = file.substring(file.lastIndexOf('/')+1); var targetName = taskName.replace(/\./g,"-"); var targetStr = ""; taskName = "minifyjs-"+targetName; var fd; var i=0; var fileStats = fs.statSync(file); var offset = fileStats.size-readmaxLen; //console.log("-1---offset:"+offset); fd = fs.openSync(file, 'r+'); if(!fd){ console.error("open file "+file+" error!"); throw "open file "+file+" error!"; return; } var readCunt = fs.readSync(fd, readBuffer, 0, readBuffer.length, offset); strReadBuf = readBuffer.toString(); //console.log("strReadBuf:"+strReadBuf); var startIndex = strReadBuf.indexOf(jsMergeFg); //console.log("indexOf(jsMergeFg):"+startIndex); if(startIndex<0){ console.error("file:"+file+" can not find js join flag:"+jsMergeFg); console.log("read finle content:"+strReadBuf); console.log("read finle length:"+strReadBuf.length); throw "file:"+file+" can not find js join flag:"+jsMergeFg; return ; } var lastIndex = strReadBuf.lastIndexOf('</script>')+'</script>'.length; var endIndex = strReadBuf.lastIndexOf('</html')+'</html>'.length; //console.log('1-startIndex'+startIndex+'---strReadBuf.length'+strReadBuf.length+'-----strReadBuf--'+strReadBuf); var joinFgStr = strReadBuf.substring(startIndex); //console.log("--1--d--joinFgStr:"+joinFgStr); var tempStrAry = []; var tempIndex = joinFgStr.indexOf("-->")+'-->'.length; startIndex += tempIndex; //console.log("1--1--joinFgStr:"+joinFgStr); //console.log("----startIndex:"+startIndex+", tempIndex:"+tempIndex); joinFgStr = joinFgStr.substring(tempIndex); //console.log("--1----joinFgStr:"+joinFgStr); var constStr = strReadBuf.substring(0, startIndex); var constBuf = new Buffer(constStr); var constLen = constBuf.length; offset += constLen; //console.log("1----constStr:"+constStr); tempStrAry = joinFgStr.split(/\r|\n/g); //提取要壓縮的JS var souceJs=[]; var sourceJsStr; for(i=0; i<tempStrAry.length; i++){ sourceJsStr = tempStrAry[i].match(/\"([^\"]+)\.js/g); if(sourceJsStr) { if(sourceJsStr[0].indexOf('"/')==0) { souceJs.push(sourceJsStr[0].replace(/^\"\//, '')); //1. 去掉 "/ }else if(sourceJsStr[0].indexOf('"')==0){ souceJs.push(sourceJsStr[0].replace(/^\"/, '')); //1. 去掉 " } } } //console.log("a---souceJs.length:"+souceJs.length+", souceJs:"+souceJs); funcChangeSourceJs2TempJsDri(file,souceJs); //console.log("souceJs.length:"+souceJs.length+", souceJs:"+souceJs); var targetMinJS = targetName+'.min.js'; var targetJoinJS = targetName+'.js'; funcJsMerge(taskName, souceJs, targetJoinJS); fistGulpTask.push(taskName); //delFiles.push(targetMinJS); var strHtml = '<script src="/sresource/js/'+targetMinJS+'" type="text/javascript"></script>'; targetStr = '\n' + strHtml; targetStr += strReadBuf.substring(lastIndex); //console.log("html:"+targetStr); endIndex = targetStr.lastIndexOf('</html')+'</html>'.length; var newLen = fileStats.size-new Buffer(joinFgStr).length+new Buffer(targetStr.substring(0,endIndex)).length; writeBuffer = new Buffer(readmaxLen-constLen); for(i=0; i<writeBuffer.length; i++){ writeBuffer[i]=13; } fs.writeSync(fd, writeBuffer, 0, writeBuffer.length, offset); writeBuffer = new Buffer(targetStr); fs.writeSync(fd, writeBuffer, 0, writeBuffer.length, offset); fs.ftruncateSync(fd, newLen); fs.closeSync(fd); } //將要合併的JS定位徹底路徑 function funcChangeSourceJs2TempJsDri(htmlFile, sourceJs){ var file = htmlFile; var relPath; var i=0; for(i=0; i<sourceJs.length; i++) { //源JS定位於sresource if (sourceJs[i].indexOf('sresource') == 0) { }else{ //相對路徑形式 ../ relPath = path.resolve(file, sourceJs[i]); sourceJs[i] = path.relative(rootDir, relPath); } } for(i=0; i<sourceJs.length; i++) { sourceJs[i] = webappDir+sourceJs[i]; } }
注意我這裏有幾個重要的點 1. 將要合併壓縮的JS放在HTML文件的尾部,有利於網頁的加載反應速度。其它JS或者HTML依賴的JS才放在頭部,如jQuery 2. 我在HTML文件中增長<!-- JS_MERGE_FLAG -->標誌,這個模塊下面的JS將會被合併爲壓縮爲一個.min.js文件。 3. 我是將html文件的尾部讀出來的,由於個人HTML文件比較大。 4. 個人工程目錄是 src/main/webapp/sresource/, 以gulpfile.js所在的目錄爲根。代碼中「sresource」字符串是與路徑有關的,我沒有提取出來(本人比較懶)。
代碼流程node
1. 將html文件的尾部讀出來 2. 查找標誌 JS_MERGE_FLAG ,從這個標誌開始提取JS 3. JS文件的路徑處理 4. 增長JS合併壓縮GULP任務 5. 修改HTML文件
好了,如今只須要發佈前在工程根目錄下,打開CMD,輸入gulp就OK了,若是配置有jenkins,只要將gulp命令配置到execute shell中便可。git
因爲本人能力水平所限,文中不免出錯,歡迎指正。另若是你們有好的實現方法請提出,學習一下github