在如今的前端開發中,先後端分離、模塊化開發、版本控制、文件合併與壓縮、mock數據等等一些本來後端的思想開始逐漸滲透到「大前端」的開發中。前端開發過程愈來愈繁瑣,當今愈來愈多的網站已經從網頁模式進化到了 Webapp 模式。它們運行在現代的高級瀏覽器裏,使用 HTML五、 CSS三、 ES6 等更新的技術來開發豐富的功能,網頁已經不只僅是完成瀏覽的基本需求,而且Webapp一般是一個單頁面應用(SPA),每個視圖經過異步的方式加載,這致使頁面初始化和使用過程當中會加載愈來愈多的 JavaScript 代碼,這給前端開發的流程和資源組織帶來了巨大的挑戰。css
前端開發和其餘開發工做的主要區別,首先是前端是基於多語言、多層次的編碼和組織工做,其次前端產品的交付是基於瀏覽器,這些資源是經過增量加載的方式運行到瀏覽器端,如何在開發環境組織好這些碎片化的代碼和資源,而且保證他們在瀏覽器端快速、優雅的加載和更新,就須要一個模塊化系統,這個理想中的模塊化系統是前端工程師多年來一直探索的難題。
html
本文須要有必定的Gulp和Webpack的基本概念,對Gulp和Webpack的使用有必定的瞭解。
同時還須要對npm或者cnpm有必定的的瞭解,對ComonJS、AMD規範有必定的的瞭解。前端
Gulp就是爲了規範前端開發流程,實現先後端分離、模塊化開發、版本控制、文件合併與壓縮、mock數據等功能的一個前端自動化構建工具。說的形象點,「Gulp就像是一個產品的流水線,整個產品從無到有,都要受流水線的控制,在流水線上咱們能夠對產品進行管理。」node
另外,Gulp是經過task對整個開發過程進行構建。react
Webpack 是當下最熱門的前端資源模塊化管理和打包工具。它能夠將許多鬆散的模塊按照依賴和規則打包成符合生產環境部署的前端資源。還能夠將按需加載的模塊進行代碼分隔,等到實際須要的時候再異步加載。經過 loader的轉換,任何形式的資源均可以視做模塊,好比 CommonJs 模塊、AMD 模塊、ES6 模塊、CSS、圖片、JSON、Coffeescript、LESS 等。webpack
簡單介紹了一下Gulp和Webpack的概念性的問題和大環境,接下來進入本文的主題,對比一下Gulp和Webpack的優缺點。將從基本概念、啓動本地Server、sass/less預編譯、模塊化開發、文件合併與壓縮、mock數據、版本控制、組件控制八個方面對Gulp和Webpack進行對比。git
首先從概念上,咱們能夠清楚的看出,Gulp和Webpack的側重點是不一樣的。程序員
Gulp側重於前端開發的整個過程的控制管理(像是流水線),咱們能夠經過給gulp配置不通的task(經過Gulp中的gulp.task()方法配置,好比啓動server、sass/less預編譯、文件的合併壓縮等等)來讓gulp實現不一樣的功能,從而構建整個前端開發流程。es6
Webpack有人也稱之爲模塊打包機,由此也能夠看出Webpack更側重於模塊打包,固然咱們能夠把開發中的全部資源(圖片、js文件、css文件等)均可以當作模塊,最初Webpack自己就是爲前端JS代碼打包而設計的,後來被擴展到其餘資源的打包處理。Webpack是經過loader(加載器)和plugins(插件)對資源進行處理的。github
另外咱們知道Gulp是對整個過程進行控制,因此在其配置文件(gulpfile.js)中配置的每個task對項目中該task配置路徑下全部的資源均可以管理。
好比,對sass文件進行預編譯的task能夠對其配置路徑下的全部sass文件進行預編譯處理:
1
2
3
4
5
|
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文件),以下圖
1
2
3
|
entry: {
app:__dirname + "/src/scripts/app.js",
}
|
而後Webpack進入該app.js
文件進行解析,app.js
文件以下圖:
1
2
3
4
5
6
|
//引入scss文件
import '../style/app.scss';
//引入依賴模塊
var greeter = 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項目的目錄結構:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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模塊(壓縮合並模塊後面再介紹)
1
|
$ npm install gulp-webpack vinyl-named -D
|
而後在Gulp的配置文件gulpfile.js中經過CommonJs規範引入gulp-webpack 模塊,並進行簡單配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
//1.引入 gulp-webpack和vinyl-named模塊
var webpack= require('gulp-webpack');
var webpack= require('vinyl-named');
//2.js 模塊化配置
var jsFiles = [
'./src/scripts/*.js',
];
gulp.task(
'packjs',function(){
gulp.src(jsFiles)
.pipe(uglify().on(
'error',function(err){
console.log('\x07',err.lineNumber,err.message);
return this.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
入口文件中有這樣一行代碼
1
|
import '../style/app.scss';
|
你當時可能產生疑問,爲何在js文件中引入scss文件呢?
這是由於Webpack是經過依賴關係進行文件管理的,因此,想要對樣式文件進行模塊化管理則必須與app.js
入口文件創建依賴關係,所以咱們將樣式文件的入口app.scss
文件引入到了app.js
中(其餘資源想要被管理,也須要這樣與app.js
入口文件創建依賴關係)。
可是這樣作很明顯的就是樣式文件經過app.js
入口文件所有都合併壓縮到js文件中了,這很顯然不是咱們想要的結果,因此咱們須要將樣式文件從js文件中剝離出來。
在項目中經過npm安裝一個extract-text-webpack-plugin的模塊
1
|
$ npm install extract-text-webpack-plugin -D
|
而後在Webpack的配置文件webpack.config.js中進行簡單配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
//1.引入extract-text-webpack-plugin模塊
var Et = 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: [
new Et('./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-minify-css模塊便可。
在項目中經過npm安裝一個gulp-minify-css的模塊
1
|
$ npm install gulp-minify-css -D
|
而後在Gulp的配置文件gulpfile.js中經過CommonJs規範引入gulp-minify-css模塊,並進行簡單配置
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//1.引入 gulp-minify-css模塊
var minifyCSS = require('gulp-minify-css');
//2.css 預處理
var cssFiles = [
'./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壓縮就實現了。
要想實現Gulp對js文件的合併壓縮須要安裝一個gulp-uglify和gulp-concat兩個模塊,前者是用於壓縮的模塊,後者是一個合併的模塊。
在項目中經過npm安裝gulp-uglify和gulp-concat模塊
1
|
$ npm install gulp-uglify gulp-concat -D
|
而後在Gulp的配置文件gulpfile.js中經過CommonJs規範引入gulp-uglify和gulp-concat模塊,並進行簡單配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
//1.引入**gulp-uglify**和**gulp-concat**模塊
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
//js 合併壓縮
var jsFiles = [
'./src/scripts/*.js',
];
gulp.task(
'packjs',function(){
gulp.src(jsFiles)
//js文件的壓縮
.pipe(uglify().on(
'error',function(err){
console.log('\x07',err.lineNumber,err.message);
return this.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的合併壓縮。
針對js和css文件的壓縮,Webpack已經內嵌了uglifyJS來完成對js與css的壓縮混淆,無需引用額外的插件。咱們只須要在Webpack配置文件中的plugins屬性中作以下配置:
1
2
3
4
5
6
7
8
|
plugins: [
new webpack.optimize.UglifyJsPlugin({ //壓縮代碼
compress: {
warnings: false
},
except: ['$super', '$', 'exports', 'require'] //排除關鍵字
})
]
|
須要注意的是:壓縮的時候須要排除一些關鍵字,不能混淆,好比$或者require,若是混淆的話就會影響到代碼的正常運行。
想要對html進行壓縮,一樣也是須要配置Webpack的配置文件,而且須要下載兩個插件HtmlWebpackPlugin和html-minifier插件:
1.在項目中經過npm安裝HtmlWebpackPlugin和html-minifier模塊
1
2
|
$ npm install HtmlWebpackPlugin -D
$ npm install html-minifier -D
|
2.而後在Webpack的配置文件webpack.config.js進行以下配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
plugins: [
new HtmlWebpackPlugin({ //根據模板插入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的預編譯來講,二者區別不是很大。Gulp是經過gulp-sass
、gulp-less
模塊進行預處理;而Webpack是經過scss-loader
、less-loader
加載器(loader)進行預處理。咱們仍是分別來看一下二者對此的實現。
以sass爲例子:
在項目中經過npm安裝一個gulp-sass的模塊
1
|
$ npm install gulp-sass -D
|
而後在Gulp的配置文件gulpfile.js中經過CommonJs規範引入gulp-sass模塊,並進行簡單配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
//1.引入 gulp-sass模塊
var sass= require('gulp-sass');
//2.css 預處理
var cssFiles = [
'./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。
一樣以sass爲例子:
在項目中經過npm安裝一個sass-loader和node-sass模塊,前者是用來加載sass相關文件的,後者是用來編譯sass文件的。另外還須要安裝另外兩個模塊css-loader和style-loader,前者是用來加載css相關文件的,後者是用來將css樣式裝填到html中的內聯樣式。
1
|
$ npm install sass-loader node-sass css-loader style-sass -D
|
而後在Webpack的配置文件webpack.config.js中進行簡單配置
1
2
3
4
5
6
7
8
9
10
11
12
|
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的預處理。
咱們都知道在前端開發中,ajax請求是須要啓動一個server的。特別是在先後端分離思想中,前端開發再也不像之前同樣過度依賴於後端開發,之前的那種前端測試ajax請求須要裝個tomcat或者其它服務器來啓動server的現象已經成爲過去式,如今咱們可使用像Gulp這類前端自動構建工具啓動一個本地server進行測試,不再收後端程序員鉗制了(開個玩笑,和後端好好溝通才能讓前端開發更方便)。那麼,咱們來分別看一下Gulp和Webpack是怎樣實現這個功能的。
在Gulp中想要啓動一個本地serve,只須要如下幾步:
在項目中經過npm安裝一個gulp-webserver的模塊
1
|
$ npm install gulp-webserver -D
|
而後在Gulp的配置文件gulpfile.js中經過CommonJs規範引入gulp-webserver模塊,並進行簡單配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
//1.引入 gulp-webserver 模塊
var webserver = 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
1
|
$ gulp
|
通過以上這三步,咱們就在Gulp中啓動了一個server了。在Gulp中啓動本地服務有一個很方便的配置,就是livereload:true
屬性的設置,設置後瀏覽器會根據你項目中資源的變化自動刷新瀏覽器(若是你的chrome瀏覽器設置該屬性後在你修改文件並保存時仍沒有自動刷新,多是你的chrome瀏覽器不支持,能夠chrome擴展程序中搜索並安裝LiveReload插件),好比:
個人gulp測試目錄結構:
index.html
1
2
3
4
5
6
7
8
9
10
11
|
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script src="/src/scripts/app.js"></script>
</body>
</html>
|
我在app.js文件中輸入如下內容,而後保存。
1
|
console.log('gulp-webserver livereload');
|
瀏覽器中控制檯上會馬上打印出一下信息:
說明瀏覽器自動刷新工程,這個小功能在咱們開發中屢試不爽。可是,這個功能是須要結合上一小節中的gulp.watch()
實時監控文件變化,而後執行合併壓縮和sass/less編譯等操做後,瀏覽器再刷新時才能保證是咱們修改後的內容。因此,livereload:true
屬性只是監控到咱們修改文件後刷新瀏覽器從新請求文件,若是咱們不從新編譯修改後的文件,瀏覽器獲取到的仍是原文件,並不會展現變化。
在Webpack中也能夠經過插件的形式安裝一個webpack-dev-server來實現達到啓動本地server的目的,具體步驟以下:
在項目中經過npm安裝一個webpack-dev-server的模塊
1
|
$ npm install -g webpack-dev-server -D
|
而後在Webpack的配置文件webpack.config.js中進行簡單配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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
1
|
$ webpack-dev-server
|
而後你就會看見命令行輸出內容不少,只要看看保證沒有Error就說明成功了。
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數據了。
Gulp中對mock數據的實現使經過NodeJS內置的fs模塊和url模塊實現的,由於Gulp自己就是基於NodeJS的。還記得第一小節「模塊化開發」中目錄結構中的那個mock目錄嗎?那就是用來儲存.json
文件的mock數據目錄。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
//1.引入 fs 和 url 模塊
var fs = require('fs');
var url = 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){
var urlObj = 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數據的功能,畢竟Webpack人家原本就是用來打包的,人家並非流程控制的,咱們能夠和Gulp對比實現其餘功能,是由於其餘功能都是在打包過程當中實現的(啓動server除外)。雖然Webpack沒有自帶mock數據的功能,可是咱們能夠藉助一些其餘手段來實現,好比說json-server,它的實現原理就是,啓動一個本地3000端口做爲mock數據的端口,而後咱們在Webpack中配置一個代理,讓全部請求代理到3000端口上去,就能夠獲取到數據了。
實現步驟:
在項目中經過npm安裝一個json-server的模塊
1
|
$ npm install -g json-server
|
能夠將在任何一個目錄下啓動json-server,爲了統一,咱們建議直接在項目根目錄啓動,將mock數據也放在項目根目錄下。
啓動json-server
1
|
$ json-server
|
json-server是一個很是強大的工具,感興趣的能夠自行google。
而後在Webpack的配置文件webpack.config.js中進行簡單配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
module.exports = {
devtool: 'eval-source-map',
entry: {
app:__dirname + "/src/scripts/app.js",
},
output: {
path: __dirname + "/prd/scripts/",
filename: "bundle.js"
},
//本地server配置
devServer: {
contentBase: __dirname,
port:8089,
colors: true,
historyApiFallback: true,
inline: true,
//重點在這裏
proxy:{
'/http://chping.website/*':{//爲正則表達式,匹配以http://chping.website開頭的url
target:
'http://localhost:3000',//代理到本地3000端口
pathRewrite:{
'^/http://chping.website':''//將http://chping.website替換爲空字符串
}
}
}
}
}
|
說明:
配置項'^/http://chping.website':''//將http://chping.website替換爲空字符串
的目的,舉例說明:
假設咱們項目中訪問的是http://chping.website/userlist
去獲取用戶列表,通過此配置項後,url爲http://localhost:3000/userlist
,不然爲http://localhost:3000/http://chping.website/userlist/userlist
。
1
|
$ webpack-dev-server
|
對於版本控制,咱們在開發過程當中,也是一個使用比較頻繁的功能,特別是開發團隊比較大的時候,這個功能就顯得更加劇要了。那麼Gulp和Webpack是具體怎樣實現的呢?
在項目中經過npm安裝gulp-rev和gulp-rev-collector模塊,前者用於生成文件的MD5碼文件和按MD5碼命名的資源文件,後者是利用MD5碼,對文件名進行替換。
1
|
$ npm install gulp-rev gulp-rev-collector -D
|
而後在Gulp的配置文件gulpfile.js中進行簡單配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//1.引入連個模塊
var rev = require('gulp-rev');
var revCollector = 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中須要版本控制的有css、js文件,不過Webpack的版本控制只實現了將css、js文件添加hash值方式命名的文件方式,修改引用路徑中的文件名需手動實現。
不過實現確實很簡單,只須要將webpack.config.js配置文件中的output.filename和plugins中的輸出文件名稱修改一下便可。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
module.exports = {
devtool: 'eval-source-map',
entry: {
app:__dirname + "/src/scripts/app.js",
},
output: {
path: __dirname + "/prd/scripts/",
filename: "[name]-[hash].js"//修改輸出文件名
},
plugins: [
new Et('./styles/[name]-[hash].css'),//修改輸出文件名
]
}
|
這樣就解決了。
組件控制本來應該放在模塊化小節或者先後小節,可是因爲實在不知道該怎樣比較,其實也沒啥可比較的,就放在最後了。
Gulp和Webpack對各自組件的管理都是使用的npm進行的組件管理,想了解更多npm組件的管理的可自行百度,或者看看這篇文章入個門《npm介紹》。
經過以上八個方面的功能對比,Gulp和Webpack基本都能知足前端自動化構建工具的任務,可是仍是看出兩個工具的側重點是不通的,Gulp側重整個過程的控制,Webpack在模塊打包方面有特別出衆。因此,Gulp + Webpack 組合使用可能更方便。