1. 程式人生 > >用gulp做一個略完整的前端打包工作~

用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

gulpgulp搭建一個前端專案

一、安裝與建立 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