在現在的前端開發中,前后端分離、模塊化開發、版本控制、文件合並與壓縮、mock數據等等一些原本后端的思想開始逐漸滲透到“大前端”的開發中。前端開發過程越來越繁瑣,當今越來越多的網站已經從網頁模式進化到了 Webapp 模式。它們運行在現代的高級瀏覽器里,使用 HTML5、 CSS3、 ES6 等更新的技術來開發豐富的功能,網頁已經不僅僅是完成瀏覽的基本需求,並且Webapp通常是一個單頁面應用(SPA),每一個視圖通過異步的方式加載,這導致頁面初始化和使用過程中會加載越來越多的 JavaScript 代碼,這給前端開發的流程和資源組織帶來了巨大的挑戰。
前端開發和其他開發工作的主要區別,首先是前端是基於多語言、多層次的編碼和組織工作,其次前端產品的交付是基於瀏覽器,這些資源是通過增量加載的方式運行到瀏覽器端,如何在開發環境組織好這些碎片化的代碼和資源,並且保證他們在瀏覽器端快速、優雅的加載和更新,就需要一個模塊化系統,這個理想中的模塊化系統是前端工程師多年來一直探索的難題。
本文需要有一定的 Gulp 和 Webpack 的基本概念,對Gulp和Webpack的使用有一定的了解。
同時還需要對npm或者cnpm有一定的的了解,對ComonJS、AMD規范有一定的的了解。
Gulp
Gulp 就是為了規范前端開發流程,實現前后端分離、模塊化開發、版本控制、文件合並與壓縮、mock數據等功能的一個前端自動化構建工具。說的形象點,“Gulp就像是一個產品的流水線,整個產品從無到有,都要受流水線的控制,在流水線上我們可以對產品進行管理。”
另外,Gulp是通過task對整個開發過程進行構建。
Webpack
Webpack 是當下最熱門的前端資源模塊化管理和打包工具。它可以將許多松散的模塊按照依賴和規則打包成符合生產環境部署的前端資源。還可以將按需加載的模塊進行代碼分隔,等到實際需要的時候再異步加載。通過 loader的轉換,任何形式的資源都可以視作模塊,比如 CommonJs 模塊、AMD 模塊、ES6 模塊、CSS、圖片、JSON、Coffeescript、LESS 等。
Gulp和Webpack功能實現對比
簡單介紹了一下Gulp和Webpack的概念性的問題和大環境,接下來進入本文的主題,對比一下Gulp和Webpack的優缺點。將從基本概念、啟動本地Server、sass/less預編譯、模塊化開發、文件合並與壓縮、mock數據、版本控制、組件控制八個方面對Gulp和Webpack進行對比。
基本概念
首先從概念上,我們可以清楚的看出,Gulp和Webpack的側重點是不同的。
Gulp側重於前端開發的 整個過程 的控制管理(像是流水線),我們可以通過給gulp配置不通的task(通過Gulp中的gulp.task()方法配置,比如啟動server、sass/less預編譯、文件的合並壓縮等等)來讓gulp實現不同的功能,從而構建整個前端開發流程。
Webpack有人也稱之為 模塊打包機 ,由此也可以看出Webpack更側重於模塊打包,當然我們可以把開發中的所有資源(圖片、js文件、css文件等)都可以看成模塊,最初Webpack本身就是為前端JS代碼打包而設計的,后來被擴展到其他資源的打包處理。Webpack是通過loader(加載器)和plugins(插件)對資源進行處理的。
另外我們知道Gulp是對整個過程進行控制,所以在其配置文件(gulpfile.js)中配置的每一個task對項目中 該task配置路徑下所有的資源 都可以管理。
比如,對sass文件進行預編譯的task可以對其配置路徑下的所有sass文件進行預編譯處理:
gulp.task('sass',function(){ gulp.src('src/styles/*.scss') .pipe(sass().on('error',sass.logError)) .pipe(gulp.dest('./build/prd/styles/'));//編譯后的輸出路徑 });
上面這個task可以對 'src/styles/*.scss'
目錄下的所有以 .scss
結尾的文件進行預處理。
Webpack則不是這樣管理資源的,它是根據模塊的 依賴關系 進行靜態分析,然后將這些模塊按照指定的規則生成對應的靜態資源(如下圖)。

通俗的說,Webpack就是需要通過其配置文件(webpack.config.js)中 entry
配置的一個入口文件(JS文件),如下圖
entry: {
app:__dirname + "/src/scripts/app.js", }
然后Webpack進入該 app.js
文件進行解析, app.js
文件如下圖:
//引入scss文件
import'../style/app.scss'; //引入依賴模塊 vargreeter =require('./Greeter.js'); document.getElementById('root').appendChild(greeter());
解析過程中,發現一個 app.scss
文件,然后根據 webpack.config.js
配置文件中的 module.loaders
屬性去查找處理 .scss
文件的loader進行處理,處理 app.scss
文件過程中,如果發現該文件還有其他依賴文件,則繼續處理 app.scss
文件的依賴文件,直至處理完成該“鏈路”上的依賴文件,然后又遇到一個 Greeter.js
模塊,於是像之前一樣繼續去查找對應的loader去處理…
所以,Webpack中對資源文件的處理是通過入口文件產生的依賴形成的,不會像Gulp那樣,配置好路徑后,該路徑下所有規定的文件都會受影響。
模塊化開發
所謂的前端模塊化開發,我的理解就是,在開發的時候,把不通的資源文件按照他的具體用途進行分類管理,在使用的時候利用CommonJS、AMD、CMD等規范將這些資源文件引入到當前文件中。然后在測試或者最后上線的時候,將這些資源文件按照一定的要求進行壓縮合並再加上版本控制處理。
可能這樣的理解或者說法值得商榷,但是個人還是覺得模塊化就是對內容的管理,是為了解耦合。
首先從Gulp入手,看看在項目中,怎樣利用模塊化的思想進行開發。下面是一個gulp項目的目錄結構:

Gulp
|——build: 項目輸出路徑
| |——prd: css、js文件輸出路徑 | |——scripts: js文件的輸出路徑 | |——styles: css文件的輸出路徑 | |——ver: 版本號相關文件 | |——index.html: 編譯后的index.html |——images: 圖片文件夾 |——mock: mock數據文件夾 |——node_modules: npm包管理文件夾 |——src: 工作目錄 | |——scripts | |——libs: 第三方依賴庫(jQuery等) | |——tpls: 模板文件 | |——utils: 工具類文件夾 | |——views: 頁面自定義js文件 | |——app.js: index.html文件的入口js | |——styles:文件和scripts文件夾下基本一致(本例中我引用了第三方框架,目錄更深,不在展示) |——gulpfile.js: gulp的配置文件 |——index.html: 主頁html文件 |——package.json: npm包管理配置文件
在實際開發過程中,在src目錄下工作,html、js和css等文件通過gulp的task配置,執行合並和壓縮后輸出到build目錄下(下面會詳細介紹合並壓縮的實現)。在詳細一點就是:
- 創建主頁html文件
- 創建與之對應的app.js入口文件和app.scss入口文件。這兩個文件只通過CommonJS規范 引入各自views文件中自定義的js(或scss)文件 ,具體邏輯不寫此文件中。
- 在views目錄下編寫js(或css)文件的邏輯代碼,其中如果多個文件需要公共邏輯或者工具方法,就可以抽離出來在util文件夾下創建對應的公共方法,然后在views中需要的js(或css)文件中通過CommonJS規范引入使用。libs目錄下的第三方庫或框架也是這個思想去引用。
- scripts目錄下的tpls文件是用來放置html模板的,引用方式和引用libs相同。
大體介紹了一下我理解的模塊化的思想,但是需要指出的是Gulp對js文件的模塊化工作是通過Webpack實現的,具體來說是通過安裝 gulp-webpack 模塊和相關的 loader 模塊進行js模塊化管理的。具體步驟如下:
-
在項目中通過npm安裝一個 gulp-webpack 、 vinyl-named 、 imports-loader 和 string-loader 模塊(壓縮合並模塊后面再介紹)
$ npm install gulp-webpack vinyl-named -D
-
然后在Gulp的配置文件gulpfile.js中通過CommonJs規范引入gulp-webpack 模塊,並進行簡單配置
//1.引入 gulp-webpack和vinyl-named模塊 varwebpack=require('gulp-webpack'); varwebpack=require('vinyl-named'); //2.js 模塊化配置 varjsFiles = [ './src/scripts/*.js', ]; gulp.task('packjs',function(){ gulp.src(jsFiles) .pipe(uglify().on('error',function(err){ console.log('\x07',err.lineNumber,err.message); returnthis.end(); })) //Webpack 對js模塊化部分 start .pipe(webpack({ output:{ filename:'[name].js' }, module:{ loaders:[{ test: /\.js$/, loader:'imports?define=>false' }, { test:/\.string$/, loader:'string' } ] } })); //Webpack 對js模塊化部分 end .pipe(concat('all.js')) .pipe(gulp.dest('./build/prd/scripts/')); });
對css文件我們也采用同js文件一樣的模塊化思想,利用sass進行模塊化開發,至於對scss文件的合並壓縮配置,下面還會詳細介紹。
接下來應該介紹一下Webpack的模塊化實現了,其實也就沒什么可以說的了,文件目錄和Gulp的基本相同,只不過實現過程中使用到的插件或者說模塊不同,配置不同而已。另外需要注意的是,Webpack對於資源文件的模塊化打包處理都是按js文件的處理方式處理的,例如還是上一小節中,你可能發現了,我在 app.js
入口文件中有這樣一行代碼
import'../style/app.scss';
你當時可能產生疑問,為什么在js文件中引入scss文件呢?
這是因為Webpack是通過依賴關系進行文件管理的,所以,想要對樣式文件進行模塊化管理則必須與 app.js
入口文件建立依賴關系,因此我們將樣式文件的入口 app.scss
文件引入到了 app.js
中(其他資源想要被管理,也需要這樣與 app.js
入口文件建立依賴關系)。
但是這樣做很明顯的就是樣式文件通過 app.js
入口文件全部都合並壓縮到js文件中了,這很顯然不是我們想要的結果,所以我們需要將樣式文件從js文件中剝離出來。
-
在項目中通過npm安裝一個 extract-text-webpack-plugin 的模塊
$ npm install extract-text-webpack-plugin -D
-
然后在Webpack的配置文件webpack.config.js中進行簡單配置
//1.引入extract-text-webpack-plugin模塊 varEt =require('extract-text-webpack-plugin'); module.exports = { //source-map調試 devtool: 'eval-source-map', //webpack入口文件配置 entry: { app:__dirname + "/src/scripts/app.js", }, //webpack出口文件配置 output: { path: __dirname + "/prd/scripts/",//輸出文件路徑配置 filename: "bundle.js"//輸出文件名配置 }, module:{ loaders:[ { test: /\.scss$/, loader: Et.extract('style','css!sass')//從js中抽離scss文件 } ] }, plugins: [ newEt('./styles/bundle.css'),//從js中抽離scss文件輸出目錄設置 ], //本地server配置 devServer: { contentBase: __dirname + '/prd/',//本地服務器所加載的頁面所在的目錄 port:8089,//本地服務端口配置 colors: true,//終端中輸出結果為彩色 historyApiFallback: true,//不跳轉 inline: true//實時刷新 } }
上面有些配置信息並不完全,下面的小節中會逐漸介紹到。這樣我們就實現了將css文件從js文件中剝離出來的目的。Webpack不但可以對css文件可以進行模塊化管理,還可以對圖片進行模塊管理,有興趣的可以自己去嘗試一下。
文件合並與壓縮
上面的模塊化中,我們提到了模塊化其實很大一部分是在做文件的合並與壓縮操作,所以我們馬上來看看Gulp和Webpack是怎樣是想文件的合並和壓縮的。
先來看看大背景,由於現在前端越來越龐大,頁面文件依賴也越來越多,所以對這些文件進行合理的合並和壓縮就志在必得。根據前面的了解,Webpack應該比Gulp更擅長文件合並和壓縮,畢竟人家被稱為 模塊打包機 嗎。
結論是正確的,Gulp可以對css文件以及js文件進行合並壓縮處理,而Webpack可以實現對css文件,js文件,html文件等進行合並壓縮和圖片的壓縮,還可以對js文件進行編譯(如es6–>es5,react jsx)等等,這些都是通過Webpack的 loader 實現的,當然這些也可以加入到Gulp中,畢竟Gulp把Webpack當做一個模塊,通過 gulp-webpack 都引入了。
Gulp合並壓縮文件
css的壓縮
要想實現Gulp對css文件的壓縮只需要安裝一個 gulp-minify-css 模塊即可。
-
在項目中通過npm安裝一個 gulp-minify-css 的模塊
$ npm install gulp-minify-css -D
-
然后在Gulp的配置文件gulpfile.js中通過CommonJs規范引入gulp-minify-css模塊,並進行簡單配置
//1.引入 gulp-minify-css模塊 varminifyCSS =require('gulp-minify-css'); //2.css 預處理 varcssFiles = [ './src/styles/usage/page/index.scss' ] gulp.task('sass',function(){ gulp.src(cssFiles) .pipe(sass().on('error',sass.logError)) .pipe(minifyCSS())//執行壓縮處理在一行 .pipe(gulp.dest('./build/prd/styles/')); });
這樣一個簡單的css壓縮就實現了。
js合並壓縮
要想實現Gulp對js文件的合並壓縮需要安裝一個 gulp-uglify 和 gulp-concat 兩個模塊,前者是用於壓縮的模塊,后者是一個合並的模塊。
-
在項目中通過npm安裝 gulp-uglify 和 gulp-concat 模塊
$ npm install gulp-uglify gulp-concat -D
-
然后在Gulp的配置文件gulpfile.js中通過CommonJs規范引入 gulp-uglify 和 gulp-concat 模塊,並進行簡單配置
//1.引入**gulp-uglify**和**gulp-concat**模塊 varuglify =require('gulp-uglify'); varconcat =require('gulp-concat'); //js 合並壓縮 varjsFiles = [ './src/scripts/*.js', ]; gulp.task('packjs',function(){ gulp.src(jsFiles) //js文件的壓縮 .pipe(uglify().on('error',function(err){ console.log('\x07',err.lineNumber,err.message); returnthis.end(); })) .pipe(webpack({ output:{ filename:'[name].js' }, module:{ loaders:[{ test: /\.js$/, loader:'imports?define=>false' }, { test:/\.string$/, loader:'string' } ] } })); //js文件的合並 .pipe(concat('all.js')) .pipe(gulp.dest('./build/prd/scripts/')); });
js的文件合並壓縮也完成了。我們再來看一下Webpack的合並壓縮。
Webpack的合並壓縮
壓縮js和css
針對js和css文件的壓縮,Webpack已經內嵌了uglifyJS來完成對js與css的壓縮混淆,無需引用額外的插件。我們只需要在Webpack配置文件中的plugins屬性中做如下配置:
plugins: [
newwebpack.optimize.UglifyJsPlugin({//壓縮代碼 compress: { warnings: false }, except: ['$super','$','exports','require']//排除關鍵字 }) ]
需要注意的是:壓縮的時候需要排除一些關鍵字,不能混淆,比如$或者require,如果混淆的話就會影響到代碼的正常運行。
html的壓縮
想要對html進行壓縮,同樣也是需要配置Webpack的配置文件,並且需要下載兩個插件 HtmlWebpackPlugin 和 html-minifier 插件:
1.在項目中通過npm安裝 HtmlWebpackPlugin 和 html-minifier 模塊
$ npm install HtmlWebpackPlugin -D
$ npm install html-minifier -D
2.然后在Webpack的配置文件webpack.config.js進行如下配置:
plugins: [
newHtmlWebpackPlugin({//根據模板插入css/js等生成最終HTML favicon:'./src/img/favicon.ico',//favicon路徑 filename:'/view/index.html',//生成的html存放路徑 template:'./src/view/index.html',//html模板路徑 inject:true,//允許插件修改哪些內容,包括head與body hash:true,//為靜態資源生成hash值 minify:{ //壓縮HTML文件 removeComments:true,//移除HTML中的注釋 collapseWhitespace:true//刪除空白符與換行符 } }) ]
HtmlWebpackPlugin插件在生成HTML時調用了 html-minifier 插件來完成對HTML的壓縮,這里我們使用兩個配置完成來移除HTML中的注釋以及空白符達到壓縮的效果。
sass/less預編譯
我們再來看看sass/less預編譯,其實就sass/less的預編譯來說,兩者區別不是很大。Gulp是通過 gulp-sass
、 gulp-less
模塊進行預處理;而Webpack是通過 scss-loader
、 less-loader
加載器(loader)進行預處理。我們還是分別來看一下兩者對此的實現。
Gulp預編譯sass/less
以sass為例子:
-
在項目中通過npm安裝一個 gulp-sass 的模塊
$ npm install gulp-sass -D
-
然后在Gulp的配置文件gulpfile.js中通過CommonJs規范引入gulp-sass模塊,並進行簡單配置
//1.引入 gulp-sass模塊 varsass=require('gulp-sass'); //2.css 預處理 varcssFiles = [ './src/styles/usage/page/**/*' //./src/styles/usage/page目錄下的所有文件 ]; gulp.task('sass',function(){ gulp.src(cssFiles) .pipe(sass().on('error',sass.logError)) .pipe(minifyCSS()) .pipe(gulp.dest('./build/prd/styles/'));//編譯后的輸出路徑 }); //3.對sass文件的修改添加監聽事件 gulp.task('watch',function(){ gulp.watch('./src/styles/**/*',['sass']); }); gulp.task('default',['watch','webserver'],function(){ console.log('所有任務隊列執行完畢'); });
這樣,一個簡單的sass預處理的task就配置完成了,然后我們還將該task加到gulp.watch()上實現了自動編譯(即修改sass文件后保存,則立即執行sass預處理),配合Gulp啟動的server則可以實現sass文件修改保存即可在瀏覽器中查看效果的目的,下一小節會介紹啟動本地server。
Webpack預編譯sass/less
同樣以sass為例子:
-
在項目中通過npm安裝一個 sass-loader 和 node-sass 模塊,前者是用來加載sass相關文件的,后者是用來編譯sass文件的。另外還需要安裝另外兩個模塊 css-loader 和 style-loader ,前者是用來加載css相關文件的,后者是用來將css樣式裝填到html中的內聯樣式。
$ npm install sass-loader node-sass css-loader style-sass -D
-
然后在Webpack的配置文件webpack.config.js中進行簡單配置
module:{ loaders:[ { test: /\.css$/,//匹配以.css結尾的文件,如果你項目不需要刻意不配置 loader: 'style!css'//這里順序必須這樣 }, { test: /\.scss$/,//匹配以.scss結尾的文件 loader: 'style!css!sass' } ] }
前面提到過,Webpack是通過文件的依賴關系進行加載分析的,所以當程序從主入口(js文件)進入后,在依賴的資源文件中發現有sass文件后,就會利用我們配置的 sass-loader 去加載,然后用 node-sass 去解析編譯成普通的css語法的樣式文件,在然后就是利用 style-loader 將樣式以內聯樣式的形式配置到html中(這里有一個問題,就是css-loader有什么用?我也沒搞明白,但是不添加會報錯,有知道的可以留言交流一下)。這樣Webpack就完成了sass的預處理。
啟動server
我們都知道在前端開發中,ajax請求是需要啟動一個server的。特別是在前后端分離思想中,前端開發不再像以前一樣過分依賴於后端開發,以前的那種前端測試ajax請求需要裝個tomcat或者其它服務器來啟動server的現象已經成為過去式,現在我們可以使用像Gulp這類前端自動構建工具啟動一個本地server進行測試,再也不收后端程序員鉗制了(開個玩笑,和后端好好溝通才能讓前端開發更方便)。那么,我們來分別看一下Gulp和Webpack是怎樣實現這個功能的。
Gulp啟動server
在Gulp中想要啟動一個本地serve,只需要以下幾步:
-
在項目中通過npm安裝一個 gulp-webserver 的模塊
$ npm install gulp-webserver -D
-
然后在Gulp的配置文件gulpfile.js中通過CommonJs規范引入gulp-webserver模塊,並進行簡單配置
//1.引入 gulp-webserver 模塊 varwebserver =require('gulp-webserver'); //2.配置server task gulp.task('webserver',function(){ gulp.src('./') .pipe(webserver({ host:'localhost', port:80, //瀏覽器自動刷新 livereload:true, //顯示文件目錄 directoryListing:{ enable: true, path:'./' }, })); }); //3.配置默認task gulp.task('default',['webserver'],function(){ console.log('啟動任務隊列執行完畢'); })
-
在命令行中啟動server
$ gulp
啟動成功:

- 在瀏覽器地址欄中輸入 localhost 打開頁面驗證。
經過以上這三步,我們就在Gulp中啟動了一個server了。在Gulp中啟動本地服務有一個很方便的配置,就是 livereload:true
屬性的設置,設置后瀏覽器會根據你項目中資源的變化自動刷新瀏覽器(如果你的chrome瀏覽器設置該屬性后在你修改文件並保存時仍沒有自動刷新,可能是你的chrome瀏覽器不支持,可以chrome擴展程序中搜索並安裝LiveReload插件),比如:
我的gulp測試目錄結構:

index.html
<!DOCTYPE html>
<htmllang="en"> <head> <metacharset="UTF-8"> <title>Document</title> </head> <body> <scriptsrc="/src/scripts/app.js"></script> </body> </html>
我在app.js文件中輸入以下內容,然后保存。
console.log('gulp-webserver livereload');
瀏覽器中控制台上會立刻打印出一下信息:

說明瀏覽器自動刷新工程,這個小功能在我們開發中屢試不爽。但是,這個功能是需要結合上一小節中的 gulp.watch()
實時監控文件變化,然后執行合並壓縮和sass/less編譯等操作后,瀏覽器再刷新時才能保證是我們修改后的內容。所以, livereload:true
屬性只是監控到我們修改文件后刷新瀏覽器重新請求文件,如果我們不重新編譯修改后的文件,瀏覽器獲取到的還是原文件,並不會展示變化。
Webpack啟動server
在Webpack中也可以通過插件的形式安裝一個 webpack-dev-server 來實現達到啟動本地server的目的,具體步驟如下:
-
在項目中通過npm安裝一個 webpack-dev-server 的模塊
$ npm install -g webpack-dev-server -D
-
然后在Webpack的配置文件webpack.config.js中進行簡單配置
module.exports = { devtool: 'eval-source-map', //webpack入口文件配置 entry: { app:__dirname + "/src/scripts/app.js", }, //webpack出口文件配置 output: { path: __dirname + "/prd/scripts/",//輸出文件路徑配置 filename: "bundle.js"//輸出文件名配置 }, //本地server配置 devServer: { contentBase: __dirname,//本地服務器所加載的頁面所在的目錄 port:8089,//本地服務端口配置 colors: true,//終端中輸出結果為彩色 historyApiFallback: true,//不跳轉 inline: true//實時刷新 } }
-
在命令行中啟動server
$ webpack-dev-server
然后你就會看見命令行輸出內容很多,只要看看保證沒有Error就說明成功了。
- 在瀏覽器地址欄中輸入 localhost:8089 測試一下。
Webpack的啟動本地服務也順利實現了,是不是也想實現像Gulp一樣瀏覽器自動刷新呀?那Webpack能不能實現呢?答案是肯定的,Webpack官方提供了一個輔助開發工具,它可以自動監控項目下的文件,一旦有修改保存操作,開發服務器就會自動運行Webpack 打包命令,幫我們自動將開發的代碼重新打包。而且,如果需要的話,還能自動刷新瀏覽器,重新加載資源。理論上好像是這樣,但是實現好像有不少限制,比如,HTML文件的自動刷新問題(html-webpack-plugin插件使用老是報錯),當本地server啟動在非output.path路徑之外時則不能自動刷新等問題,等我再學習學習再說,或者有知道的可以留言討論。
而這個輔助工具就是 webpack-dev-server ,它主要提供兩個功能:一是為靜態文件提供server服務,二是自動刷新和熱替換(HMR)。所以想實現如Gulp一樣的功能也是可以的,只需要在 $ webpack-dev-server
后面添加 --inline --hot
即可。需要注意的是 --inline
是自動刷新,同時在第二部中的devServer屬性中有一個 inline:true 需要配置;而 --hot
是熱替換( 詳細了解熱替換 、 了解webpack-dev-server 、 webpack-dev-server )。
通過對比來看,好像Webpack的 webpack-dev-server 比Gulp的 gulp-server 功能要強一些。因為通過上面可以看出 webpack-dev-server 有兩個大功能:一是為靜態文件提供server服務,二是自動刷新( 自動刷新其實需要兩步:1.修改文件后,文件自動編譯{包括合並壓縮或者語法編譯等},2.刷新瀏覽器請求最新編譯后的文件 )和熱替換(HMR);而 gulp-server 雖然提供了啟動本地server的能力和僅自動刷新瀏覽器的能力,缺少一個文件自動編譯的能力,這需要借助其他模塊實現(上一小節已介紹,結合gulp.watch()實時監控文件變化,並編譯)。
另外需要注意的是,實際開發中發現 webpack-dev-server 實現自動刷新的時候,並沒有執行自動編譯,只是將修改的內容合並壓縮等處理后發送給了瀏覽器,並造成了已經編譯的現象,但是通過build/prd/scripts目錄下的bundle.js(合並壓縮后的輸出文件)文件,可以發現內容並沒有編譯(對於Webpack還是不熟悉,好多問題等待解決)。
mock數據
在現在前后端分離的思想中,前端和后端耦合度越來越小,現在唯一需要前后端密切聯系的就是借口的定義和數據格式的確定。一般在項目開始前,前端和后端將項目中的接口和數據格式全部確定下來(當然項目需求變更就需要臨時確立這些共識了),然后前端就可以自己mock數據了。
Gulp實現mock數據
Gulp中對mock數據的實現使通過NodeJS內置的fs模塊和url模塊實現的,因為Gulp本身就是基於NodeJS的。還記得第一小節“模塊化開發”中目錄結構中的那個mock目錄嗎?那就是用來儲存 .json
文件的mock數據目錄。
- 配置Gulp的gulpfile.js文件
//1.引入 fs 和 url 模塊
varfs =require('fs'); varurl =require('url'); //2.重新配置一下上一小節的server gulp.task('webserver',function(){ gulp.src('./') .pipe(webserver({ host:'localhost', port:80, livereload:true, directoryListing:{ enable: true, path:'./' }, //mock數據配置 middleware:function(req,res,next){ varurlObj = url.parse(req.url,true); switch(urlObj.pathname) { case'/pro/getPro': res.setHeader('Content-Type','application/json;charaset=utf-8'); fs.readFile('./mock/list.json',function(err,data){ //上面list.json路徑使用相對路徑,絕對路徑前台無法獲取數據 res.end(data); }); return; case'/web/getUser': //.... return; } next(); } })); });
具體來說,就是通過NodeJS攔截http請求,根據請求URL來模擬后端做出處理后返回不同的數據。
Webpack實現mock數據
完善中。。。
版本控制
對於版本控制,我們在開發過程中,也是一個使用比較頻繁的功能,特別是開發團隊比較大的時候,這個功能就顯得更加重要了。那么Gulp和Webpack是具體怎樣實現的呢?
Gulp實現版本控制
-
在項目中通過npm安裝 gulp-rev 和 gulp-rev-collector 模塊,前者用於生成文件的MD5碼文件和按MD5碼命名的資源文件,后者是利用MD5碼,對文件名進行替換。
$ npm install gulp-rev gulp-rev-collector -D
-
然后在Gulp的配置文件gulpfile.js中進行簡單配置
//1.引入連個模塊 varrev =require('gulp-rev'); varrevCollector =require('gulp-rev-collector'); // 2.版本號控制 gulp.task('ver',function(){ gulp.src(cssFiles) .pipe(rev())//產生MD5碼 .pipe(gulp.dest('./build/prd/styles/'))//重命名文件 .pipe(rev.manifest())//產生版本信息的json文件 .pipe(gulp.dest('./build/ver/styles/')); gulp.src(jsFiles) .pipe(rev()) .pipe(gulp.dest('./build/prd/scripts/')) .pipe(rev.manifest()) .pipe(gulp.dest('./build/ver/scripts/')); }) //動態修改html中對css和js文件的修改 gulp.task('html',function(){ gulp.src(['./build/ver/**/*','./build/*.html']) .pipe(revCollector()) .pipe(gulp.dest('./build/')); })
Gulp實現版本控制很方便,將這兩個task加入gulp.watch()中,即可實現修改保存文件實時自動修改版本的功能。
Webpack實現版本控制
Webpack中需要版本控制的有css、js文件,不過Webpack的版本控制只實現了將css、js文件添加hash值方式命名的文件方式,修改引用路徑中的文件名需手動實現。
不過實現確實很簡單,只需要將webpack.config.js配置文件中的output.filename和plugins中的輸出文件名稱修改一下即可。
module.exports = { devtool: 'eval-source-map', entry: { app:__dirname + "/src/scripts/app.js", }, output: { path: __dirname + "/prd/scripts/", filename: "[name]-[hash].js"//修改輸出文件名 }, plugins: [ newEt('./styles/[name]-[hash].css'),//修改輸出文件名 ] }
這樣就解決了。
組件控制
組件控制原本應該放在模塊化小節或者前后小節,但是由於實在不知道該怎樣比較,其實也沒啥可比較的,就放在最后了。
Gulp和Webpack對各自組件的管理都是使用的npm進行的組件管理,想了解更多npm組件的管理的可自行百度,或者看看這篇文章入個門《npm介紹》。
總結
通過以上八個方面的功能對比,Gulp和Webpack基本都能滿足前端自動化構建工具的任務,但是還是看出兩個工具的側重點是不通的,Gulp側重整個過程的控制,Webpack在模塊打包方面有特別出眾。所以,Gulp + Webpack 組合使用可能更方便。
很長的一篇總結文章,前前后后花了兩天時間終於寫完了,還有很多測試沒做,並且還有很多疑問沒解決。慢慢學習,慢慢在補充修改吧。