技巧集:http://www.gulpjs.com.cn/docs/recipes/css
其實無非就是利用各類gulp插件、node腳本對項目文件作各類IO操做,只是備忘,須要的話,仍是本身從新寫最合適。 html
毛病:若是須要task之間的同步依賴關係,那麼上一個task function裏面須要有return;各個task的依賴,應該用gulpSequence作拉平。前端
var gulp = require('gulp'), sass = require('gulp-sass'), postcss = require('gulp-postcss'), autoprefixer = require('autoprefixer'), browserSync = require('browser-sync').create(), open = require('gulp-open'), del = require('del'), usemin = require('gulp-usemin'), // useref = require('gulp-useref'),// 這個相對目錄有問題 媽的 不用了 zip = require('gulp-zip'), gulpRevAll = require('gulp-rev-all'), revReplace = require("gulp-rev-replace"), uglify = require('gulp-uglify'), minifyCss = require('gulp-minify-css'), Replace = require('gulp-replace'), htmlmin = require('gulp-htmlmin'), gulpSequence = require('gulp-sequence'), argv = require('yargs').argv; // node命令傳入的參數整合參數 /**************************配置項**************************/ var _opt = { src: 'app/', // src: 'dist/sce/app/', // devHost:"sns-operating-dev.sohuno.com", // devHost: "dev.w.sohu.com", //默認當前局域網ip // startPath: '/view/intro.html', startPath: '/view/index.html', dest: 'dist/', tem: 'tem/', revDelay: 5, //單位秒 staticInCDN: true, //默認放cdn cdnPath: '//sns_business.cdn.sohusce.com/square-unlogin-v3/', // staticProxyPath: '/h5static/',//須要代理的靜態資源路徑標記 sce: { // releaseUrl: 'http://fe.w.sohu.com/h5apps/sns-square-test/view/intro.html', //線上或測試環境的項目url manageUrl: '//console.sce.sohuno.com/apps/versions?appid=', path: 'sce/', yamlPath: 'sce/app.yaml', appPath: 'sce/app/', confPath: 'sce/conf/', test: { //暫僅測試環境 這裏須要優化配置 gulp發佈的時候帶上環境參數 如gulp r --test/product appId: 212250773, sceHost: '//sns-square-unlogin-v30-test.sce.sohuno.com', backendHost: { 'sns-core': 'sns-api.apps.sohuno.com', //sns-data-api-test.sce.sohuno.com sns-api.apps.sohuno.com msapi.t.sohu.com // 'sns-data':'sns-data-api-test.sce.sohuno.com' } }, product: { appId: 985464923, sceHost: '//sns-square-unlogin-v30.sce.sohuno.com', backendHost: { 'sns-core': 'sns-api.apps.sohuno.com', // 'sns-data':'sns-data.sohuno.com' } } } }; /**************************本地開發Server**************************/ var _env = _opt.sce[Object.keys(argv)[1]] ? Object.keys(argv)[1] : 'test'; console.log("● serverPath:" + _opt.src); console.log("● serverEnv:" + _env); // 靜態服務器 gulp.task('serve', ['sass'], function() { var proxyMiddleware = require('http-proxy-middleware'); var proxy = proxyMiddleware(['/sns-core'], { target: 'http://' + _opt.sce[_env].backendHost['sns-core'], pathRewrite: { '^/sns-core/(.*)': '/$1' }, changeOrigin: true, headers: { host: _opt.sce[_env].backendHost['sns-core'], origin: 'http://' + _opt.sce[_env].backendHost['sns-core'] } }); //禁止開發server的緩存 var proxyNoCache = function(req, res, next) { res.setHeader('CacheControl', 'no-cache'); res.setHeader('Pragma', 'no-cache'); res.setHeader('Expires', '-1'); res.setHeader('ETag', Date.now()); //禁止304 next(); } browserSync.init({ server: { baseDir: _opt.src //_opt.dest//''//''// _opt.dest,//_opt.dest src }, ui: { port: 3030 }, host: _opt.devHost, //hosts文件設置代理到開發機IP server種cookie用 open: "external", // startPath: _opt.startPath, ghostMode: false, //關掉多設備同步 middleware: [proxy, proxyNoCache] }); gulp.watch(_opt.src + "/static/scss/*.scss", ['sass']); gulp.watch([_opt.src + "/static/js/**", _opt.src + "/static/img/**", _opt.src + "/**/*.html" ]).on('change', browserSync.reload); }); // gulp.task('rrr', function() { // return gulp.src([_opt.src + "/static/scss/sns-base.scss"], { // base: _opt.src + "/static/scss/" // }) // .pipe(Replace(/\n[\t\u0020]*?\/\/.+?\n/g,"\n\n")) // .pipe(gulp.dest(_opt.src + "/static/acss/")) // }); gulp.task('sass', function() { var postPlugins = [ autoprefixer() //browserlist read from package.json //取值https://github.com/ai/browserslist#queries ]; return gulp.src([_opt.src + "/static/scss/**/*.scss"], { base: _opt.src + "/static/scss/" }) // auto append night mode(.night),color base scss/_const.scss // 之後抽象成一個插件 // 最好的實現不是預先刪除註釋,而應該是不去替換註釋裏的夜色纔對 @20180119 // 有個bug 啓動的時候能夠注掉 修改scss後的reload任務很差使 // 幹掉scss中的註釋 避免下面的夜色模式替換 把註釋裏的也給替換了致使scss結構錯亂報錯 .pipe(Replace(/([\s;])\/\/.+?(?=\n)/g, function(s, m1) { //刪掉空字符或者;後面的單行註釋內容; //這個正則引擎 不支持確定逆序表達式 (?<=[\s;]) 只能function return m1了 return m1; })) .pipe(Replace(/\/\*.+?\*\//g,''))//刪掉塊級註釋 咦尼瑪 這個怎麼很差使 見main.css //_const.scss中色值變量命名 需遵循規範 $c-grey1:#000; $c-night-grey1:#454545; .pipe(Replace(/([\w-]+?\s*?\:.*\$c-.+?;)/g, function(s, m1, m2) { // console.log('----\r\n'+m1+'\r\n----\r\n'); var m1_night = m1.replace(/\$c-/g, '$c-night-'); return m1 + '\n @at-root .night &{' + m1_night + '}\n'; })) .pipe(sass()) .on('error', function(err) { console.log('Less Error!', err.message); this.emit('end'); }) .pipe(postcss(postPlugins)) .pipe(gulp.dest(_opt.src + "/static/css/")) .pipe(browserSync.reload({ stream: true })); }); // gulp.task('openUrl', function() { // console.log('----打開sce線上url,fiddler代理至本地'); // gulp.src(__filename) // .pipe(open({ uri: _opt.sce.releaseUrl, app: "chrome" })); // }); /**************************臨時工具處理**************************/ //圖片壓縮 非尺寸 gulp.task('imgmin1', function() { var imagemin = require('gulp-imagemin'); // gulp.src(_opt.src+'/img/*.+(png)') gulp.src(_opt.src + '/static/img/**/*.png', { base: _opt.src }) .pipe(imagemin()) .pipe(gulp.dest(_opt.src)); }); /**************************打包發佈正式方案**************************/ gulp.task('delDest', function() { // console.log("● 環境:"+_env); var path = _opt.dest; console.log('----清空目錄' + path); return del(path); }); gulp.task('tem', ['delDest'], function() { var path = _opt.tem; console.log('----清空目錄' + path); return del(path); }); gulp.task('delTem', function() { var path = _opt.tem; console.log('----清空目錄' + path); return del(path); }); gulp.task('delSceApp', function() { var path = _opt.sce.appPath; console.log('----清空目錄' + path); return del(path); }); // 拷貝文件 gulp.task('copy2tem', ['delDest', 'delTem', 'sass'], function() { console.log('----拷貝文件到臨時文件夾'); return gulp.src([ _opt.src + '/static/**', _opt.src + '/view/**', '!' + _opt.src + '/static/scss/**' ], { base: _opt.src }) .pipe(gulp.dest(_opt.tem)); }); // 合併 gulp.task('usemin', ['copy2tem'], function() { // return gulp.src([ _opt.tem + 'view/**/*.html' ], { base: _opt.tem }) .pipe(usemin({ //成功的先不上報處理了 jsAttributes: { // onload: 'window.srcLoadLog && srcLoadLog(this)', onerror: 'window.srcErrorLog && srcErrorLog(this)' }, cssAttributes: { // onload: 'window.srcLoadLog && srcLoadLog(this)', onerror: 'window.srcErrorLog && srcErrorLog(this)' } })) .pipe(gulp.dest(_opt.tem)); }); //js壓縮 gulp.task('jsmin', ['usemin'], function() { console.log('----壓縮js'); return gulp.src([ _opt.tem + '/static/js/**/*.js', '!' + _opt.tem + '/static/js/**/*.min.js' ], { base: _opt.tem }) // .pipe(uglify()) .pipe(uglify({ compress: { // "quote-keys":true//ie8 // properties:false, drop_console: true } // quote_keys: true // beautify : { beautify: false, ascii_only: true, quote_keys: true } })) .pipe(gulp.dest(_opt.tem)); }); //css壓縮 gulp.task('cssmin', ['usemin'], function() { console.log('----壓縮CSS'); return gulp.src([ _opt.tem + '/static/css/**/*.css', '!' + _opt.tem + '/static/css/*.min.css' ], { base: _opt.tem }) .pipe(minifyCss()) .pipe(gulp.dest(_opt.tem)); }); // 加MD5戳 gulp.task('revAll', ['jsmin', 'cssmin'], function() { // console.log('----加MD5戳&替換相互引用(延時' + _opt.revDelay + 's後進行下一任務)'); // var revAll = new RevAll({ // dontRenameFile: [/^\/static\/img\/ad-avatar/]//ad-avatar前端不直接用 手動替換後上傳cdn給server下發用 // // ,dontGlobal:[] // // ,dontSearchFile:[/^\/static\/js\//]//dontSearchFile 對js/xx/下的路徑文件 不作內容中的引用替換處理 // }); gulp.src([_opt.tem + '/*/**'], { ///static/** base: _opt.tem }) .pipe(gulpRevAll.revision({ dontRenameFile: [/^\/view\//, /^\/static\/img\/ad-avatar/] //ad-avatar前端不直接用 手動替換後上傳cdn給server下發用 // ,dontGlobal:[] , dontSearchFile: [/^\/static\/js\//] //dontSearchFile 對js/xx/下的路徑文件 不作內容中的引用替換處理 })) .pipe(gulp.dest(_opt.tem)) .pipe(gulpRevAll.versionFile()) .pipe(gulp.dest(_opt.tem)) .pipe(gulpRevAll.manifestFile()) .pipe(gulp.dest(_opt.tem)); }); //htmlmin gulp.task('htmlmin', function() { // console.log('----htmlmin'); return gulp.src([ _opt.tem + '/**/*.html' // '!'+_opt.dest+'/tpls/write/write.html' ], { base: _opt.tem }) .pipe(htmlmin({ collapseWhitespace: true, removeComments: true, minifyCSS: true, minifyJS: true })) .pipe(gulp.dest(_opt.tem + '/')); }); //加cdn前綴 gulp.task('cdnPre', ['htmlmin'], function() { if (!_opt.staticInCDN) return false; console.log('----加CDN前綴'); return gulp.src([ _opt.tem + '/**/*.html' // ,_opt.dest + '/static/js/common/myLib.*.js' ], { base: _opt.tem }) //下面往後寫成通配符嚴格匹配 path/**.xxx 上面的js就能夠寫成all js了 .pipe(Replace(/"[./]*static\//g, '"' + _opt.cdnPath)) //有點風險 往後優化 .pipe(gulp.dest(_opt.tem + '/')); }); //imgmin - 這個任務時間太長 依賴創建不起來,r完了還會在壓着,因此從gulp 抽成單獨一項任務,gulp serve前手動搞 // gulp.task('imgmin',['copy2tem'], function() { // var imagemin = require('gulp-imagemin'); // // gulp.src(_opt.src+'/img/*.+(png)') // gulp.src(_opt.tem + '/static/img/**/*.png', { // base: _opt.tem // }) // .pipe(imagemin()) // .pipe(gulp.dest(_opt.tem)); // }); //拷貝sce基礎文件至dist gulp.task('sce_base2dist', function() { console.log('----拷貝sce基礎文件到發佈目錄'); return gulp.src([ _opt.sce.path + "/**" ], { base: _opt.sce.path }) .pipe(gulp.dest(_opt.dest + "/sce")); }); // 根據環境修改sce appId gulp.task('sceConfigInit', ['sce_base2dist'], function() { console.log('----sce配置初始化'); // return gulp.src(_opt.sce.yamlPath) return gulp.src([ _opt.dest + _opt.sce.yamlPath, _opt.dest + _opt.sce.confPath + '/nginx_server.inc' ], { base: _opt.dest }) //backendHost 下面正則優化 加強匹配的嚴謹性--這裏之後改爲寫入而不是 替換是否是能好一些 .pipe(Replace(/appid: \d+/, 'appid: ' + _opt.sce[_env].appId)) .pipe(Replace(/server_sns-core(?=[;/ ])/g, _opt.sce[_env].backendHost['sns-core'])) .pipe(gulp.dest(_opt.dest)); }); // 拷貝文件 gulp.task('tem2sceDist', ['cdnPre'], function() { console.log('----拷貝項目文件到dist/sce目錄'); return gulp.src([ _opt.tem + "/**", '!' + _opt.tem + 'rev-*.json' ], { base: _opt.tem }) .pipe(gulp.dest(_opt.dest + _opt.sce.appPath)); }); // 靜態資源壓縮zip for cdn gulp.task('static2zip', ['cdnPre'], function() { if (!_opt.staticInCDN) return false; console.log('----靜態資源to zip for cdn'); var cdn_project_name = 'toCDN_' + _opt.cdnPath.match(/\/\/(.+?)\.cdn/)[1] + '_' + _opt.cdnPath.replace(/.+\.com\//, "").replace(/\//g, "") + ".zip"; // var cdn_project_name = 'toCDN_' + _opt.staticProxyPath.replace(/\//g, "") + ".zip"; return gulp.src([ _opt.tem + '/static/**' ], { base: _opt.tem + '/static/' }) .pipe(zip(cdn_project_name)) .pipe(gulp.dest(_opt.dest)); //剔除rev map文件、zip打包文件 須要優化 }); // sce項目zip gulp.task('sce2zip', ['tem2sceDist', 'sceConfigInit'], function() { console.log('----sce to zip'); var zip_name = 'sce_' + _opt.sce[_env].appId + '.zip'; return gulp.src([_opt.dest + _opt.sce.path + '/**']) .pipe(zip(zip_name)) .pipe(gulp.dest(_opt.dest)); }); //發佈 gulp.task('packContinue', ['sce2zip', 'static2zip'], function() { console.log('----清除臨時文件'); // 清除臨時文件 del(_opt.tem); console.log('● 環境:' + _env); console.log('● 前端項目已發佈到' + _opt.dest); if (_opt.staticInCDN) console.log('○ 靜態資源zip請上傳至:' + _opt.cdnPath); console.log('○ sce zip請上傳至:' + _opt.sce.manageUrl + _opt.sce[_env].appId); console.log('● sce前端服務host:' + _opt.sce[_env].sceHost); console.log('----完成!'); }); // 發佈-cdn gulp.task('r', ['revAll'], function(cb) { // console.log("----環境:"+_env); setTimeout(function() { //延時太挫 待優化 https://github.com/gulpjs/gulp/issues/96 gulpSequence('packContinue', cb); }, _opt.revDelay * 1000); //revAll 延時 }); // 發佈-local gulp.task('r:local', ['revAll'], function(cb) { _opt.staticInCDN = false; // console.log("----環境:"+_env); setTimeout(function() { //延時太挫 待優化 https://github.com/gulpjs/gulp/issues/96 gulpSequence('packContinue', cb); }, _opt.revDelay * 1000); //revAll 延時 });
優勢:模塊化拆分、回調拉平、功能配置化node
let gulp = require('gulp'), config = require('./config.js'), del = require('del'), requireDir = require('require-dir'), chalk = require('chalk'), runSequence = require('run-sequence'); console.log('Waiting For Gulp Tasks Loading ...' + '\n'); let { NODE_ENV: env, CDN: cdn } = process.env; // 遞歸引入gulp/tasks目錄下的文件,該操做比較耗時(稍弱些的機器配置 14s左右) requireDir('./gulp/tasks', { recurse: true }); if (env !== 'dev') { console.log('\n\n/*********************** 打包開始,當前環境爲:' + chalk.blue.bold(env) + ' ***********************/' + '\n'); } gulp.task('build', function(cb) { //默認不放 CDN del.sync(config.temp); del.sync(config.dist); runSequence(['svg'], ['eslint', 'ES6', 'imgMin', 'fileInclude', 'sceInit'], ['sass'], ['uncss'], ['sprite'],['jscss2dist'], ['usemin'], ['cssmin', 'jsmin', 'htmlmin'], ['revision'], ['cdnPre'], ['delRedundant'], ['zip'], ['openUrl'], function() { if (cdn === 'true') console.log('○ 靜態資源zip請上傳至:' + config.cdnPath); console.log('○ sce zip請上傳至:' + config.sce.manageUrl + config.sce[env].appId); console.log('\n\n/*********************** 打包結束,當前環境爲:' + chalk.blue.bold(env) + ' ***********************/' + '\n'); }); }) //不作jscss合併等工做 直接打包 gulp.task('build:dev', function(cb) { del.sync(config.temp); del.sync(config.dist); runSequence(['svg'], ['eslint', 'ES6', 'imgMin', 'fileInclude', 'sceInit'], ['sass'], ['sprite'],'temp2dist', ['zip'], ['openUrl'], function() { if (cdn === 'true') console.log('○ 靜態資源zip請上傳至:' + config.cdnPath); console.log('○ sce zip請上傳至:' + config.sce.manageUrl + config.sce[env].appId); console.log('\n\n/*********************** 打包結束[純開發包],當前環境爲:' + chalk.blue.bold(env) + ' ***********************/' + '\n'); }); }) gulp.task('dev', function(cb) { del.sync(config.temp); config.buryPointSwitch = false; config.isImgOptmize = false; runSequence(['svg'], ['fileInclude', 'eslint', 'ES6', 'imgMin'], ['sass'], ['sprite'], ['dev-server'], cb); }); //打包到dist 且啓動目錄改到dist(用來本地測試打包後的頁面運行 注:須要去dev-server改一下serverPath) gulp.task('dev:dist', function(cb) { del.sync(config.temp); config.buryPointSwitch = false; config.isImgOptmize = false; // runSequence(['svg'], ['eslint', 'ES6', 'imgMin', 'fileInclude', 'sceInit'], ['sass'], ['sprite'],'temp2dist', ['dev-server'], cb); runSequence( ['delRedundant'], ['svg'], ['eslint', 'ES6', 'imgMin', 'fileInclude', 'sceInit'], ['sass'], ['uncss'], ['sprite'], ['usemin'], ['cssmin', 'jsmin', 'htmlmin'], ['revision'],'dev-server', cb); });