前言 前端自動化構建工具從最開始的grunt, gulp, fis等到現在比較流行的webpack可謂層出不窮,個人還是比較傾向於gulp,雖然有的時候會因為某個插件的配置問題頭疼很久,但不可否認gulp真的很靈活,而且個人覺得它和node結合起來比較舒服,再有對項目目錄結構的要求比較低,即使再老再 ...
前言
前端自動化構建工具從最開始的grunt, gulp, fis等到現在比較流行的webpack可謂層出不窮,個人還是比較傾向於gulp,雖然有的時候會因為某個插件的配置問題頭疼很久,但不可否認gulp真的很靈活,而且個人覺得它和node結合起來比較舒服,再有對項目目錄結構的要求比較低,即使再老再亂的項目也可以通過它進行整理和自動化構建。這裡用本公司的一個老項目舉例子。
項目目錄
因為是老項目,各種資源的引用亂七八糟,首先花費大量時間把項目中所有靜態資源全部整理至新的目錄中,並且把原來項目中的路徑全部替換掉。現在新的靜態資源目錄為項目根目錄Public下,如下圖:
初始化npm
安裝node,完了繼續npm init,下一步下一步生成package.json,裡面包含了我們項目所需要的各種模塊的依賴和基本信息。這裡拿我的package.json舉例:
{ "name": "test", "version": "1.0.0", "description": "test web gulp", "main": "gulpfile.js", "dependencies": { "gulp": "^3.9.1", "gulp-clean-css": "^3.9.0", "gulp-concat": "^2.6.0", "gulp-csso": "^1.1.0", "gulp-filter": "^4.0.0", "gulp-jshint": "^2.0.0", "gulp-minify-html": "^1.0.6", "gulp-rename": "^1.2.2", "gulp-rev-collector": "^1.2.2", "gulp-zip": "^4.0.0", "jshint": "^2.9.5" }, "devDependencies": { "arr-flatten": "^1.1.0", "array-differ": "^1.0.0", "array-uniq": "^1.0.3", "beeper": "^1.1.1", "dateformat": "^2.2.0", "expand-range": "^2.0.0", "expand-tilde": "^2.0.2", "extend-shallow": "^2.0.1", "gulp-aliyun-oss": "^0.1.1", "gulp-clean": "^0.3.2", "gulp-make-css-url-version": "0.0.13", "gulp-minify-css": "^1.2.4", "gulp-replace": "^1.0.0", "gulp-rev": "^7.1.2", "gulp-uglify": "^1.5.4", "has-gulplog": "^0.1.0", "lodash": "^3.0.0", "lodash._reescape": "^3.0.0", "lodash._reevaluate": "^3.0.0", "lodash._reinterpolate": "^3.0.0", "lodash.assignwith": "^4.2.0", "lodash.template": "^4.4.0", "multipipe": "^0.1.2", "object-assign": "^3.0.0", "parse-filepath": "^1.0.1", "repeat-element": "^1.1.2", "replace-ext": "^0.0.1", "run-sequence": "^1.2.2", "through2": "^2.0.0", "vinyl": "^0.5.0" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "hxj", "license": "ISC" }
安裝依賴
這個沒什麼說的,安裝相應功能的gulp插件,npm install package(安裝的包名,如:gulp) —save-dev然後回車。
這裡有一個很多人一直弄不明白的問題,就是為什麼有時候加-save, 有時候加--save-dev,那麼他們的區別到底是什麼:
—save-dev(也可以縮寫成-D)輸出的會出現在devDependencies,代表著是開發調試時的依賴,等到項目真正發佈的時候不會真正出現在項目中。
—save(也可以縮寫成-S)輸出的會出現在dependencies,代表著是發佈後的依賴,等到項目真正發佈的時候會真正出現在項目中,缺少它們項目會運行不了。
構建gulp任務
這裡直接貼代碼,構建出來的靜態文件全部上傳到阿裡雲oss,因為公司項目是用jenkins部署的,所以在jenkins中會專門有一個shell腳本用來執行gulp構建任務:
#!/bin/bash if [ -f gulpfile.js ] ; then /usr/bin/gulp buildBeta else echo "未找到gulpfile.js" exit 1 fi #!/bin/bash tar czf ROOT.tar.gz *
完整代碼:
var gulp = require("gulp"); var runSequence = require('run-sequence'); // 按順序逐個同步地運行 Gulp 任務 var oss = require('gulp-aliyun-oss'); // 阿裡雲上傳文件 var cssmin = require('gulp-minify-css'); // 壓縮css文件 var uglify = require('gulp-uglify'); //js壓縮 var rev = require('gulp-rev'); // 為靜態文件隨機添加一串hash值, 解決cdn緩存問題 var clean = require('gulp-clean'); // 刪除文件及文件夾 var revCollector = require('gulp-rev-collector'); //gulp-rev的插件 ,用於html模板更改引用路徑 // 配置開發環境, 預設為測試環境 var ENV = "beta"; var config = { beta: { accessKeyId: '******', accessKeySecret: '******', region: '******', bucket: '******', prefix: 'www/', domain: '//www.beta.example.com/www/' }, prod: { accessKeyId: '******', accessKeySecret: '******', region: '******', bucket: '******', prefix: 'www/', domain: '//www.example.com/www/' } } // 配置輸入輸出路徑 var path = { base: "Public/static", input: { html: "app/Tpl/**/*.html", css: "Public/static/styles/**/*.css", js: "Public/static/script/**/*.js", images: "Public/static/images/**/*", }, output: "Public/target" } function params() { return (ENV == 'prod') ? config.prod : config.beta; } // 壓縮圖片 gulp.task('imgmin', function() { return gulp.src(path.input.images, { base: path.base }) .pipe(rev()) .pipe(gulp.dest(path.output)) .pipe(rev.manifest()) .pipe(gulp.dest(path.output + "/rev/images")); }); // 壓縮css gulp.task('cssmin', function() { return gulp.src(path.input.css, { base: path.base }) .pipe(cssmin({ advanced: false, //類型:Boolean 預設:true [是否開啟高級優化(合併選擇器等)] compatibility: 'ie7', //保留ie7及以下相容寫法 類型:String 預設:''or'*' [啟用相容模式; 'ie7':IE7相容模式,'ie8':IE8相容模式,'*':IE9+相容模式] keepBreaks: false, //類型:Boolean 預設:false [是否保留換行] keepSpecialComments: '*' //保留所有特殊首碼 當你用autoprefixer生成的瀏覽器首碼,如果不加這個參數,有可能將會刪除你的部分首碼 })) .pipe(rev()) .pipe(gulp.dest(path.output)) .pipe(rev.manifest()) .pipe(gulp.dest(path.output + "/rev/styles")); }); // 壓縮js gulp.task('jsmin', function() { return gulp.src(path.input.js, { base: path.base }) .pipe(uglify({ mangle: true, compress: true })) .pipe(rev()) .pipe(gulp.dest(path.output)) .pipe(rev.manifest()) .pipe(gulp.dest(path.output + "/rev/script")); }); // css中的引用資源路徑替換 gulp.task('replaceImgPath', function() { return gulp.src( [ path.output + "/rev/images/*.json", path.output + "/styles/**/*.css" ] ) .pipe(revCollector({ replaceReved: true // 用來說明模板中已經被替換的文件是否還能再被替換,預設是false })) .pipe(gulp.dest(path.output + "/styles")); }); // 上傳靜態文件到oss gulp.task('uploadOss', function(cb) { var options = { accessKeyId: params().accessKeyId, accessKeySecret: params().accessKeySecret, region: params().region, bucket: params().bucket, prefix: params().prefix, ossOpt: { headers: { 'Cache-Control': 'no-cache' } } }; return gulp.src(['./Public/target/**/*', '!Public/target/rev/**/*']).pipe(oss(options)); }) /** * 頁面模版資源路徑替換 */ gulp.task('replaceHtml', function() { return gulp.src([ path.output + "/rev/**/*.json", path.input.html ]) .pipe(revCollector({ replaceReved: true, dirReplacements: { '/Public/static/': params().domain + '/', '/Public/static/': params().domain + '/', '/Public/static/': params().domain + '/', } })) .pipe(gulp.dest('./app/Tpl/')); }); /** * 刪除輸出目錄 */ gulp.task('del', function() { return gulp.src([path.output], { read: false }).pipe(clean()); }); //構建 gulp.task('buildBeta', function(done) { ENV = "beta"; runSequence( ['imgmin'], ['cssmin'], ['jsmin'], ['replaceImgPath'], ['uploadOss'], ['replaceHtml'], ['del'], done); }) gulp.task('buildProd', function(done) { ENV = "prod"; runSequence( ['imgmin'], ['cssmin'], ['jsmin'], ['replaceImgPath'], ['uploadOss'], ['replaceHtml'], ['del'], done); })