用gulp做一個略完整的前端打包工作~
分模組,每個模組都有獨立的頁面和靜態檔案,並將所有靜態檔案打在一個資料夾下,
一些常用變數可以進行替換,並可進行簡單的頁面動態生成,
生產環境打包與線上環境打包分開進行,
靜態檔案進行壓縮合並,加md5以及cdn,
wap的靜態檔案與web端分離,wap的頁面檔案沒有的繼承web端的頁面檔案,有的要用它本身。
打包由grunt換成gulp。
整體的路徑要像這樣:
好了,那我們開始,首先當然是要安裝gulp
npm install gulp --save-dev
然後你需要在你的環境里加一個gulpfile.js的檔案。
然後我們為了高大上一點,給弄個簡易的手冊出來:
直接console.log輸出就好了···
// 說明
gulp.task('help',function () {
console.log(' gulp build 檔案打包');
console.log(' gulp watch 檔案監控打包');
console.log(' gulp help gulp引數說明');
console.log(' gulp server 測試server');
console.log(' gulp -p 生產環境(預設生產環境)');
console.log(' gulp -d 開發環境');
console.log(' gulp -m <module> 部分模組打包(預設全部打包)' );
});
/* 預設 */
gulp.task('default',function () {
gulp.start('help');
});
然後在你的控制檯輸入 gulp help或者 gulp build 就可以看到效果啦
然後我們要建立我們的build任務啦~
首先我們需要接收引數判斷是開發打包還是生產打包。這裡需要一個外掛-- yargs,以及我們以後需要用到的工具類的外掛:lodash(用於運算元組,當然它不僅僅是有這樣的用處)和 path(用於寫路徑),用npm像上面那樣加到你的環境中,
並且在你的gulpfile檔案中宣告它們:
/* 載入工具 */
var argv = require ('yargs').argv,
_ = require('lodash'),
path = require('path');
記得之後載入的外掛都需要這樣宣告。
我們新建一個叫build的task
//建立任務
gulp.task('build', function() {
});
在裡面獲取一下控制檯輸入的引數:
var evr = argv.p || !argv.d; //生產環境為true,開發環境為false,預設為true
var mod = argv.m || 'all';//模組明,預設為全部
這樣你在控制檯輸入 gulp build -p 或者 gulp build -p -m t1這樣就可以在裡面獲得引數啦。
然後我們需要進行一些打包的配置,先在寫一個叫FileConfig的js檔案,在裡面寫我們需要的檔案配置資訊:
"use strict";
var path = require('path');
/* 環境資訊 */
var source = 'source',
develop = 'develop',
production = 'production';
/* src路徑 */
var src = {
tpl: 'tpl/**',
css: 'styles/**/*.less',
js: 'lib/**/*.js',
html: '/**.html',
img: 'images/**'
}
/* 模組資訊 */
var modules = {
"t1": {
src: 't1',
dest: 't1',
name: 't1',
css_files: 'styles/app.less'
},
"t2": {
src:'t2',
dest: 't2',
name: 't2'
},
"index": {
src:'index',
dest: 'index',
name: 'index'
},
"common": {
src:'common',
dest: 'common',
name: 'common'
}
};
然後在下面寫個方法:
var FileConfig = function () {
};
為了省事兒,直接在exports的時候就new了它···
module.exports = new FileConfig();
之後我們的一些配置資訊全部從FileConfig這個方法裡取,比如要模組資訊的話:
FileConfig.prototype.modules = function () {
return modules;
};
之後的具體實現就不再囉嗦啦。
然後我們回到gulpfile.js檔案下,宣告他,之後會用到。
然後我們就要對html,css,js,img進行處理啦,這裡會用到很多外掛,一次性的列舉出來,用法我在後面的註釋中寫了:
// 載入外掛
var gulp = require('gulp'),
browserify = require('browserify'),//這裡用不上,管理js依賴的
source = require('vinyl-source-stream'),//同樣這裡用不上,和上面那個一起的
uglify = require('gulp-uglify'),//混淆js
clean = require('gulp-clean'),//清理檔案
notify = require('gulp-notify'),//加控制檯文字描述用的
buffer = require('vinyl-buffer'),
less = require('gulp-less'),//轉換less用的
autoprefixer = require('gulp-autoprefixer'),//增加私有變數字首
minifycss = require('gulp-minify-css'),//壓縮
concat = require('gulp-concat'),//合併
fileinclude = require('gulp-file-include'),// include 檔案用
template = require('gulp-template'),//替換變數以及動態html用
rename = require('gulp-rename'),//重新命名
webserver = require('gulp-webserver'),//一個簡單的server,用python的SimpleHttpServer會鎖資料夾
imagemin = require('gulp-imagemin'),//圖片壓縮
gulpif = require('gulp-if'),//if判斷,用來區別生產環境還是開發環境的
rev = require('gulp-rev'),//加MD5字尾
revReplace = require('gulp-rev-replace'),//替換引用的加了md5字尾的檔名,修改過,用來加cdn字首
addsrc = require('gulp-add-src'),//pipeline中途新增資料夾,這裡沒有用到
del = require('del'),//也是個刪除···
vinylPaths = require('vinyl-paths'),//操作pipe中檔案路徑的,加md5的時候用到了
runSequence = require('run-sequence');//控制task順序
好啦,為了省事兒,寫個物件字面量的方法集:
/* 打包方法 */
var teemoGulp = {
/* html打包 */
buildHtml : function () {},
/* css 打包 */
buildCss : function () {},
/* js打包 */
buildJs : function () {},
/* img打包 */
buildImg: function () {},
/* md5打包 */
buildMd5: function () {}
}
然後我們先說簡單的,js打包,只需要初始路徑和打包後路徑就好啦:
/* js打包 */ buildJs : function () { var src = arguments[0],dest = arguments[1], flag = arguments[2] return gulp.src(src) .pipe(gulp.dest(dest)) .pipe(uglify()) .pipe(rename({ suffix: '.min' })) .pipe(gulp.dest(dest)); }
其中flag是之前的這個var evr = argv.p || !argv.d; //生產環境為true,開發環境為false,預設為true,這個比較簡單,先把原始檔案拷貝一份,在混淆壓縮加.min字尾存一份。
img打包也很簡單
/* img打包 */
buildImg: function () {
var src = arguments[0],dest = arguments[1], flag = arguments[2]
return gulp.src(src)
.pipe(gulpif(flag, imagemin()))
.pipe(gulp.dest(dest));
},
這裡注意一下用到了 gulpif 根據環境來判定是否需要做 圖片的壓縮操作,因為這項操作比較費時間,開發環境下就不進行了。
css打包和html打包需要用到一些存好的變數,比如,如果我們需要每個頁面的keywords是一樣的:
<meta name="keywords" content="<%- keywords %>">
我們就需要給這些變數一個配置的地方,這個和fileconfig是一樣的,就不再說了。然後替換這些變數我們要用到 gulp-template,他繼承了lodash的template的用法,也就是說,他可以識別js程式碼以及lodash的一些用法。
而當我們想增加一些檔案時,就要用到gulp-file-include,或者你直接改lodash,讓他支援html程式碼也可以,不過我不贊成這樣做。
他的用法類似這樣:
@@include('t1/tpl/menu.html')
整體的html打包程式碼是這樣:
/* html打包 */
buildHtml : function () {
var src = arguments[0],dest = arguments[1], flag = arguments[2], options = arguments[3];
return gulp.src(src)
.pipe(fileinclude({
basepath:basePath.source
}))
.pipe(template(options,{
//interpolate: /\{-([\s\S]+?)-\}/g
}))
.pipe(gulp.dest(dest))
},
template預設的包裹變數的標示是 <%-%>當然你可以用 interpolate去配置這些。
好啦,方法我們寫好了,下面是引用他們,我們需要在寫一個方法,
var build = funciton () {
}
然後獲取引數資訊,並進行必要的配置,讓他們可以按照我們想要的方式輸出。
var evr = options.evr,mod = options.mod; if(!modules[mod]) mod = 'all'; /* 路徑初始化 */ fileConfig.init(evr); gulp.task('clean', function() { if(mod === 'all') { var clean_path = path.join( evr&& basePath.production || basePath.develop, '/'); return gulp.src([clean_path], {read:false}) .pipe(clean()); } }); /* 獲取要build的模組 */ var parts = []; if(mod === 'all') { parts = modules; }else { parts = _.pick(modules,mod); }
之後我們迴圈遍歷modules,建立相應的task
/* 分別對模組進行建立 */
var list = [];
for( var key in parts){
(function (key) {//閉個包
var options = fileConfig.getModule(parts[key]);
/* js建立 */
gulp.task(key+'_js',function () {
return teemoGulp.buildJs(options.js.src,options.js.dest,evr);
});
/* css建立 */
gulp.task(key+'_css',function () {
return teemoGulp.buildCss(options.css.src,options.css.dest,evr, teemoConfig, options.css.filename);
});
/* html建立 */
gulp.task(key+'_html',function () {
return teemoGulp.buildHtml(options.html.src,options.html.dest,evr, teemoConfig);
});
/* img建立 */
gulp.task(key+'_img',function () {
return teemoGulp.buildImg(options.img.src,options.img.dest,evr);
});
/* 模組建立 */
gulp.task(key+'_module',function(cb) {
runSequence(
[key+'_html',key+'_css',key+'_js',key+'_img'],
cb
);
} );
})(key);
list.push(key+'_module');
}
這裡用到了runSequence,它制定了task的執行順序,因為如果不這樣做,gulp預設是儘可能的併發執行,就有可能出現 clean沒執行完,後續就開始執行的結果,這裡注意吧task的回撥放在runSequence的最後,保證內部的task執行完,再執行完本身。
當然如果比較簡單的,你可以用task的第二個引數來控制task的執行順序,這裡不囉嗦啦。
然後把list返還給你最初的 build
var list = Build({
evr: evr,
mod: mod
});
var md5 = evr&& 'md5' || [];
runSequence(
'clean',list, 'md5',cb
);
然後順序執行即可。
之後到了md5的階段,md5打包用rev外掛即可,但是他預設的md5碼是10個,你可以去修改gulp-rev\node_modules\rev-hash路徑下的index.js檔案,或者乾脆做個變數在你的filegulp裡配置,單我覺得沒必要,就偷懶這裡改一下啦。我喜歡用16位
在之後需要把這些加了md5的檔名字換給你引用這些檔案的地方,就用到了 rev-replace。
rev在改路徑時候會生成一個對映表,你用rev.manifest()即可儲存在相應的目錄裡,然後rev-replace用這個檔案替換掉你目標檔案的路徑即可。
至於cdn,也可以用revReplace裡的prefix屬性去加字首,不過他只支援字串,如果我們是有多個cdn域名的話,返回給他的可能是一個方法,所以這裡我們需要改一下rep-replace檔案。
找到gulp-rev-replace下的index.js檔案。
在第36行加一句
var prefix = typeof options.prefix === 'function' ? options['prefix'](path.basename(file.path)) : options.prefix;
用prefix替換掉一下用到options.prefix的地方。你需要在第60行左右做同樣的事情:
if (options.manifest) {
// Read manifest file for the list of renames.
options.manifest.on('data', function (file) {
var manifest = JSON.parse(file.contents.toString());
Object.keys(manifest).forEach(function (srcFile) {
var prefix = typeof options.prefix === 'function' ? options['prefix'](path.basename(srcFile)) : options.prefix; //這句是加的
renames.push({
unreved: canonicalizeUri(srcFile),
reved: prefix + canonicalizeUri(manifest[srcFile]),
prefix: prefix //這句也是後加的
});
});
});
options.manifest.on('end', replaceContents);
}
else {
replaceContents();
}
而且你會發現在之後替換的時候也用到了這個,所以你要他當局部變數傳進renames裡去。想上面寫的那樣,因為下面一句用到了他:
if (rename.prefix) { contents = contents.split('/' + rename.prefix).join(rename.prefix + '/'); //這句也改了 }
它這替換方式也挺喪良心的···
這樣,我們就可以往裡面傳方法了~
網上找個算cdn域名的方法:
/*生成hash */
hashFnv32a : function(str, asString, seed) {
/*jshint bitwise:false */
var i, l,
hval = (seed === undefined) ? 0x811c9dc5 : seed;
for (i = 0, l = str.length; i < l; i++) {
hval ^= str.charCodeAt(i);
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
}
if( asString ){
// Convert to 8 digit hex string
return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
}
return hval >>> 0;
}
然後我們就可以進行md5加cdn的打包操作了:
/* md5打包 */
buildMd5: function () {
var vp = vinylPaths();
return gulp.src(path.join(basePath.production, '/**/{images,lib,styles}/**/*.*'))
.pipe(vp)
.pipe(rev())
.pipe(gulp.dest(basePath.production))
.pipe(rev.manifest())
.pipe(gulp.dest(basePath.production))
.on('end',function () {
var manifest = gulp.src(path.join(basePath.production, "/rev-manifest.json"));
gulp.src(path.join(basePath.production, '/**/*.{css,html}'))
.pipe(revReplace({
manifest: manifest,
prefix: function (f) {
//cdn域名
var cdns = ["s1","s2","s3","s4"];
var fileHashCode = teemoGulp.hashFnv32a(f);
if(fileHashCode <0 ){
fileHashCode = 0;
}
var cdn = cdns[fileHashCode % cdns.length];
return 'http://'+cdn+'.tm.sogoucdn.com/w/20141209'
}
}))
.pipe(gulp.dest(basePath.production))
.on('end',function () {
del(vp.paths);
del(path.join(basePath.production, "/rev-manifest.json"));
})
})
},
這樣,整個的打包就完成了啦,壓縮混淆合併加md5加cdn就全都搞定了。
至於加wap的資料夾,就在做一遍之前的操作即可,記得html要在做一遍覆蓋操作,也就是三遍。
需要注意的是你改過的外掛需要自己存到特定的包管理的地方去,或者存到自己的github上也行,配好ssh就能下。
最後你需要一個 測試的server,這個很好配:
/* server */
gulp.task('server', function() {
var evr = argv.p || !argv.d;
gulp.src(evr?basePath.production:basePath.develop)
.pipe(webserver({
livereload: true,
directoryListing: true,
open: true
}));
});
不過如果你要測試cdn的話,就只能自己配nginx了,gulp-server上倒是能配代理,不過我沒用過,應該也好用。
這樣,所有的工作就完成了,這樣做還是很方便的,比如,主管要求生產環境和開發環境的路徑上要在家 一層路徑,那麼我們直接修改fileConfig裡面的配置就可以:
/* 環境資訊 */ var source = 'source', develop = 'build/develop', production = 'build/production';
相關推薦
用gulp做一個略完整的前端打包工作~
分模組,每個模組都有獨立的頁面和靜態檔案,並將所有靜態檔案打在一個資料夾下, 一些常用變數可以進行替換,並可進行簡單的頁面動態生成, 生產環境打包與線上環境打包分開進行, 靜態檔案進行壓縮合並,加md5以及cdn, wap的靜態檔案與web端分離,wap的頁面檔案
做一個合格的前端,gulp自動化構建工具入門教程
安裝完成 基本 合成 node.js 文件替換 mage 9.png basename 加載 我的新作觀點網http://www.guandn.com (觀點網是一個獵獲新奇、收獲知識、重在獨立思考的網站),它前端js、css的壓縮、合並、md5命名等就使用了gulp自動化
[Python] 用python做一個遊戲輔助指令碼,完整思路
一、說明 簡述:本文將以4399小遊戲《寵物連連看經典版2》作為測試案例,通過識別小圖示,模擬滑鼠點選,快速完成配對。對於有興趣學習遊戲指令碼的同學有一定的幫助。 執行環境:Win10/Python3.5。 主要模組:win32gui(識別視窗、視窗置頂等操作)、PIL(螢幕截圖)、nump
【gulp】用gulp搭建一個前端專案
一、安裝與建立 1.安裝node:https://nodejs.org/zh-cn/ 2.安裝gulp:npm install gulp -g 3.新建一個資料夾用來存放專案 4.在命令列進入建立的資料夾輸入 gulp init即可 5.新建一
怎麽用cookie做一個選項卡?
eight splay i++ 作用 code round tab 多網站 個性化 什麽是cookie? Cookies雖然一般都以英文名呈現,但是它還是有一個可愛的中文名“小甜餅”。Cookies是指服務器暫存放在你的電腦裏的txt格式的文本文件資料,主要用
繞過010Editor網絡驗證(用python做一個仿真http server真容易,就幾行代碼)
headers redirect 如果 table 本地 align cnn 破解版 resp 010Editor是一款非常強大的十六進制編輯器,尤其是它的模板功能在分析文件格式時相當好用!網上現在也有不少010Editor的破解版,如果沒錢或者舍不得花錢買授權的話,去官方
星期四、星期五、星期一—用GUI做一個簡易的交易系統
his 換行 巧克力 cal show .get ner 文本域 array 1、登錄界面 package org.eclipse.wb.swing; //登錄界面 import java.awt.BorderLayout;import java.awt.EventQue
用vue做一個酷炫的menu
方法 tar ges enter 導入 count https 簡單 ren 寫在前面 最近看到一個非常酷炫的menu插件,一直想把它鼓搗成vue形式,誰讓我是vue的死灰粉呢,如果這都不算愛??。??開個小玩耍,我們一起來探索黑魔法吧。觀看本教程的讀者需要
如何做一個好的前端重構工程師
騰訊 tro 審視 書籍 工作 ie8 性能優化 不斷學習 來看 這裏的“重構”指的是將設計圖(比如PSD)轉換為html + css + js。 用這個標題,是因為前一段時間組裏有一個開放式討論:怎樣才算一個好重構? 其實,"好"與"壞"向來都是相對的,因為每個人眼中看待
【python基礎】用字典做一個小型的查詢數據庫
import oot 字符 odin 參數錯誤 err 輸出 put 異常 例子來源於《python基礎教程》第三版,57p 該例子主要是使用字典的方式,實現一個小型的數據庫,通過查詢字典的鍵值來獲取用戶的信息。 本人修改了部分代碼。 #!/usr/bin/python3
懶人動手,用python做一個基礎翻譯重新命名器(破解百度翻譯反爬手段)
想法: 在做開發的時候,經常需要命名各種變數,方法/函式,類,包,庫等。 走一遍流程就是:想好要起的名字,比如“非常帥氣”; 然後上翻譯網站,比如百度翻譯,有道翻譯; 將中文輸入並讓其翻譯成英文,此時就得出一個“very handsome”的單詞; 根據駝峰命名法,我們最後需要得
用 Vue 做一個簡單的購物app
有意思 應用程序 其中 ins com 簡單的 node.js 引入 大神 前言 最近在學習Vue的使用。看了官方文檔之後,感覺挺有意思的。於是著手做了一個簡單的購物app。這是我第一次在這個網站上寫分享,如有不當之處,請多多指教。 一整個項目寫下來,最大的感覺就是組件式開
用java做一個簡單的打字遊戲
Java也是可以做桌面程式的。只不過需要執行在裝有JDK的電腦環境上,所以應用不是很廣泛,但是用來提高自身的程式碼邏輯還是可以的!偶有一天看到金山的打字通,就想起何不做個簡單的打字遊戲用來練練手。於是就有了下文 首先建一個類MyTyping,只有main方法 執行main方法
用HTML5做一個個人網站,此文僅展示個人主頁介面。內附原始碼下載地址
html5 ,用css去修飾自己的個人主頁 程式碼如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitio
用列表做一個登入系統 功能實現:註冊與登入系統
list1=[]# 儲存使用者名稱 list2=[] #儲存密碼 while True: print('歡迎來到登入頁面') print('1:登入\n2:註冊\n3:退出') xz = int(input('請選擇:')) if xz ==
發現電腦上還裝著liteide,就用golang做一個TCP通訊測試
1、參考https://www.cnblogs.com/yin5th/p/9274495.html server端 main.go package main import ( "fmt" "net" ) func main() { // simple t
用OpenPose做一個運動量測量器
通過openpose獲得肢體關鍵點的位置資訊,利用脖子位置作為中心點求得相對位置,然後用左肩到右肩距離進行歸一化,將經過上述處理後的位置作為輸出。利用攝像頭獲得每一幀的上述輸出,相減得到各個關節的移
用Java做一個及時翻譯工具
平時看英文文件或者查詢資料的時候,遇到了不懂的單詞,就要去百度,然後就會很麻煩。於是就想到用Java寫一個及時翻譯的小工具!預期的實現效果: 雙擊選中一個單詞,按下Ctrl+C進行復制 然後馬上顯示出對應單詞的中文翻譯首先基本思路是這樣的: 首先獲取系統剪下板的
用java做一個簡單的萬年曆
一個簡單的萬年曆製作 簡單介紹萬年曆的各功能實現: 1.首先鍵盤輸入查詢的年份和月份 Scanner sc = new Scanner(System.in); System.ou
用Python做一個聊天機器人
最近在使用騰訊語音合成時發現了一個有趣的東西:智慧閒聊 好奇之下點了進去,發現是一個智慧聊天的功能。然後就順勢根據這個api寫了一個簡單的聊天機器人。 好了,廢話不多說,下面來一步一步實現聊天機器人 1:在騰訊ai開放平臺建立一個應用。 2:獲得該應用的app_id